All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 0/3] perf intel-pt: Add PEBS-via-PT side-band
@ 2021-09-07 16:39 Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Adrian Hunter @ 2021-09-07 16:39 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
	linux-perf-users, linux-kernel

Hi

PEBS output to Intel Processor Trace was introduced with Atom
processors based on Tremont.  Currently there is software support
only for a single PEBS-via-PT event.

Here is support for multiple PEBS-via-PT events.

The first patch is the kernel change which adds a new event,
namely PERF_RECORD_AUX_OUTPUT_HW_ID which contains the counter
index.  That is output when the PEBS-via-PT event is enabled in hardware.
There is an optimization, to report the index only when it changes
for the event.  That will work only so long as all PEBS-via-PT
events are scheduled together, which they are for a recording
session because they are in a single group.

Also no attribute bit is used to select the new event, so a new
kernel is not compatible with older perf tools.  The assumption
being that PEBS-via-PT is sufficiently esoteric that users will not
be troubled by this.

The second patch adds the usual boiler plate to perf tools for
a new event.

The third patch adds support for processing the new event by
perf tool's Intel PT decoder.


Changes in V3:
    perf/x86: Add new event for AUX output counter index
	Do not set assign callback unless x86_pmu.intel_cap.pebs_output_pt_available

Changes in V2:
    perf/x86: Add new event for AUX output counter index
	Use callback from x86_assign_hw_event


Adrian Hunter (3):
      perf/x86: Add new event for AUX output counter index
      perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID
      perf intel-pt: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID

 arch/x86/events/core.c                     |  6 +++
 arch/x86/events/intel/core.c               | 16 ++++++
 arch/x86/events/perf_event.h               |  1 +
 include/linux/perf_event.h                 |  1 +
 include/uapi/linux/perf_event.h            | 15 ++++++
 kernel/events/core.c                       | 30 +++++++++++
 tools/include/uapi/linux/perf_event.h      | 15 ++++++
 tools/lib/perf/include/perf/event.h        |  6 +++
 tools/perf/Documentation/perf-intel-pt.txt |  7 ++-
 tools/perf/builtin-inject.c                |  4 +-
 tools/perf/builtin-record.c                |  2 +-
 tools/perf/util/event.c                    | 18 +++++++
 tools/perf/util/event.h                    |  5 ++
 tools/perf/util/intel-pt.c                 | 85 ++++++++++++++++++++++++++++--
 tools/perf/util/machine.c                  | 10 ++++
 tools/perf/util/machine.h                  |  2 +
 tools/perf/util/session.c                  |  5 ++
 tools/perf/util/tool.h                     |  1 +
 18 files changed, 222 insertions(+), 7 deletions(-)


Regards
Adrian

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-07 16:39 [PATCH V3 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
@ 2021-09-07 16:39 ` Adrian Hunter
  2021-09-07 17:45   ` Liang, Kan
  2021-10-15  9:31   ` [tip: perf/core] " tip-bot2 for Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 3/3] perf intel-pt: " Adrian Hunter
  2 siblings, 2 replies; 13+ messages in thread
From: Adrian Hunter @ 2021-09-07 16:39 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
	linux-perf-users, linux-kernel

PEBS-via-PT records contain a mask of applicable counters. To identify
which event belongs to which counter, a side-band event is needed. Until
now, there has been no side-band event, and consequently users were limited
to using a single event.

Add such a side-band event. Note the event is optimised to output only
when the counter index changes for an event. That works only so long as
all PEBS-via-PT events are scheduled together, which they are for a
recording session because they are in a single group.

Also no attribute bit is used to select the new event, so a new
kernel is not compatible with older perf tools.  The assumption
being that PEBS-via-PT is sufficiently esoteric that users will not
be troubled by this.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---

Changes in V3:
	Do not set assign callback unless x86_pmu.intel_cap.pebs_output_pt_available

Changes in V2:
	Use callback from x86_assign_hw_event


 arch/x86/events/core.c          |  6 ++++++
 arch/x86/events/intel/core.c    | 16 ++++++++++++++++
 arch/x86/events/perf_event.h    |  1 +
 include/linux/perf_event.h      |  1 +
 include/uapi/linux/perf_event.h | 15 +++++++++++++++
 kernel/events/core.c            | 30 ++++++++++++++++++++++++++++++
 6 files changed, 69 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 2a57dbed4894..be33423e9762 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -66,6 +66,8 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_enable_all,  *x86_pmu.enable_all);
 DEFINE_STATIC_CALL_NULL(x86_pmu_enable,	     *x86_pmu.enable);
 DEFINE_STATIC_CALL_NULL(x86_pmu_disable,     *x86_pmu.disable);
 
+DEFINE_STATIC_CALL_NULL(x86_pmu_assign, *x86_pmu.assign);
+
 DEFINE_STATIC_CALL_NULL(x86_pmu_add,  *x86_pmu.add);
 DEFINE_STATIC_CALL_NULL(x86_pmu_del,  *x86_pmu.del);
 DEFINE_STATIC_CALL_NULL(x86_pmu_read, *x86_pmu.read);
@@ -1215,6 +1217,8 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 	hwc->last_cpu = smp_processor_id();
 	hwc->last_tag = ++cpuc->tags[i];
 
+	static_call_cond(x86_pmu_assign)(event, idx);
+
 	switch (hwc->idx) {
 	case INTEL_PMC_IDX_FIXED_BTS:
 	case INTEL_PMC_IDX_FIXED_VLBR:
@@ -2005,6 +2009,8 @@ static void x86_pmu_static_call_update(void)
 	static_call_update(x86_pmu_enable, x86_pmu.enable);
 	static_call_update(x86_pmu_disable, x86_pmu.disable);
 
+	static_call_update(x86_pmu_assign, x86_pmu.assign);
+
 	static_call_update(x86_pmu_add, x86_pmu.add);
 	static_call_update(x86_pmu_del, x86_pmu.del);
 	static_call_update(x86_pmu_read, x86_pmu.read);
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 7011e87be6d0..a555e7c2dce9 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2402,6 +2402,12 @@ static void intel_pmu_disable_event(struct perf_event *event)
 		intel_pmu_pebs_disable(event);
 }
 
+static void intel_pmu_assign_event(struct perf_event *event, int idx)
+{
+	if (is_pebs_pt(event))
+		perf_report_aux_output_id(event, idx);
+}
+
 static void intel_pmu_del_event(struct perf_event *event)
 {
 	if (needs_branch_stack(event))
@@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
 	return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
 }
 
+static void intel_aux_output_init(void)
+{
+	/* Refer also intel_pmu_aux_output_match() */
+	if (x86_pmu.intel_cap.pebs_output_pt_available)
+		x86_pmu.assign = intel_pmu_assign_event;
+}
+
 static int intel_pmu_aux_output_match(struct perf_event *event)
 {
+	/* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
 	if (!x86_pmu.intel_cap.pebs_output_pt_available)
 		return 0;
 
@@ -6301,6 +6315,8 @@ __init int intel_pmu_init(void)
 	if (is_hybrid())
 		intel_pmu_check_hybrid_pmus((u64)fixed_mask);
 
+	intel_aux_output_init();
+
 	return 0;
 }
 
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index e3ac05c97b5e..76436a55d9ba 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -726,6 +726,7 @@ struct x86_pmu {
 	void		(*enable_all)(int added);
 	void		(*enable)(struct perf_event *);
 	void		(*disable)(struct perf_event *);
+	void		(*assign)(struct perf_event *event, int idx);
 	void		(*add)(struct perf_event *);
 	void		(*del)(struct perf_event *);
 	void		(*read)(struct perf_event *event);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fe156a8170aa..6f4a15660651 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1398,6 +1398,7 @@ perf_event_addr_filters(struct perf_event *event)
 }
 
 extern void perf_event_addr_filters_sync(struct perf_event *event);
+extern void perf_report_aux_output_id(struct perf_event *event, u64 hw_id);
 
 extern int perf_output_begin(struct perf_output_handle *handle,
 			     struct perf_sample_data *data,
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index f92880a15645..c89535de1ec8 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -1141,6 +1141,21 @@ enum perf_event_type {
 	 */
 	PERF_RECORD_TEXT_POKE			= 20,
 
+	/*
+	 * Data written to the AUX area by hardware due to aux_output, may need
+	 * to be matched to the event by an architecture-specific hardware ID.
+	 * This records the hardware ID, but requires sample_id to provide the
+	 * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT
+	 * records from multiple events.
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u64				hw_id;
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_AUX_OUTPUT_HW_ID		= 21,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 744e8726c5b2..79241b6e57c7 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9073,6 +9073,36 @@ static void perf_log_itrace_start(struct perf_event *event)
 	perf_output_end(&handle);
 }
 
+void perf_report_aux_output_id(struct perf_event *event, u64 hw_id)
+{
+	struct perf_output_handle handle;
+	struct perf_sample_data sample;
+	struct perf_aux_event {
+		struct perf_event_header        header;
+		u64				hw_id;
+	} rec;
+	int ret;
+
+	if (event->parent)
+		event = event->parent;
+
+	rec.header.type	= PERF_RECORD_AUX_OUTPUT_HW_ID;
+	rec.header.misc	= 0;
+	rec.header.size	= sizeof(rec);
+	rec.hw_id	= hw_id;
+
+	perf_event_header__init_id(&rec.header, &sample, event);
+	ret = perf_output_begin(&handle, &sample, event, rec.header.size);
+
+	if (ret)
+		return;
+
+	perf_output_put(&handle, rec);
+	perf_event__output_id_sample(event, &handle, &sample);
+
+	perf_output_end(&handle);
+}
+
 static int
 __perf_event_account_interrupt(struct perf_event *event, int throttle)
 {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V3 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID
  2021-09-07 16:39 [PATCH V3 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
@ 2021-09-07 16:39 ` Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 3/3] perf intel-pt: " Adrian Hunter
  2 siblings, 0 replies; 13+ messages in thread
From: Adrian Hunter @ 2021-09-07 16:39 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
	linux-perf-users, linux-kernel

The PERF_RECORD_AUX_OUTPUT_HW_ID event provides a way to match AUX output
data like Intel PT PEBS-via-PT back to the event that it came from, by
providing a hardware ID that is present in the AUX output.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
 tools/include/uapi/linux/perf_event.h | 15 +++++++++++++++
 tools/lib/perf/include/perf/event.h   |  6 ++++++
 tools/perf/builtin-inject.c           |  4 +++-
 tools/perf/builtin-record.c           |  2 +-
 tools/perf/util/event.c               | 18 ++++++++++++++++++
 tools/perf/util/event.h               |  5 +++++
 tools/perf/util/machine.c             | 10 ++++++++++
 tools/perf/util/machine.h             |  2 ++
 tools/perf/util/session.c             |  5 +++++
 tools/perf/util/tool.h                |  1 +
 10 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index f92880a15645..c89535de1ec8 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -1141,6 +1141,21 @@ enum perf_event_type {
 	 */
 	PERF_RECORD_TEXT_POKE			= 20,
 
+	/*
+	 * Data written to the AUX area by hardware due to aux_output, may need
+	 * to be matched to the event by an architecture-specific hardware ID.
+	 * This records the hardware ID, but requires sample_id to provide the
+	 * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT
+	 * records from multiple events.
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u64				hw_id;
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_AUX_OUTPUT_HW_ID		= 21,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
index 095d60144a70..acc4fa065ec7 100644
--- a/tools/lib/perf/include/perf/event.h
+++ b/tools/lib/perf/include/perf/event.h
@@ -289,6 +289,11 @@ struct perf_record_itrace_start {
 	__u32			 tid;
 };
 
+struct perf_record_aux_output_hw_id {
+	struct perf_event_header header;
+	__u64			hw_id;
+};
+
 struct perf_record_thread_map_entry {
 	__u64			 pid;
 	char			 comm[16];
@@ -414,6 +419,7 @@ union perf_event {
 	struct perf_record_auxtrace_error	auxtrace_error;
 	struct perf_record_aux			aux;
 	struct perf_record_itrace_start		itrace_start;
+	struct perf_record_aux_output_hw_id	aux_output_hw_id;
 	struct perf_record_switch		context_switch;
 	struct perf_record_thread_map		thread_map;
 	struct perf_record_cpu_map		cpu_map;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6ad191e731fc..ac6c570029e3 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -815,7 +815,8 @@ static int __cmd_inject(struct perf_inject *inject)
 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
 		inject->tool.auxtrace	    = perf_event__process_auxtrace;
 		inject->tool.aux	    = perf_event__drop_aux;
-		inject->tool.itrace_start   = perf_event__drop_aux,
+		inject->tool.itrace_start   = perf_event__drop_aux;
+		inject->tool.aux_output_hw_id = perf_event__drop_aux;
 		inject->tool.ordered_events = true;
 		inject->tool.ordering_requires_timestamps = true;
 		/* Allow space in the header for new attributes */
@@ -882,6 +883,7 @@ int cmd_inject(int argc, const char **argv)
 			.lost_samples	= perf_event__repipe,
 			.aux		= perf_event__repipe,
 			.itrace_start	= perf_event__repipe,
+			.aux_output_hw_id = perf_event__repipe,
 			.context_switch	= perf_event__repipe,
 			.throttle	= perf_event__repipe,
 			.unthrottle	= perf_event__repipe,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b3509d9d20cc..71a08eeea252 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1409,7 +1409,7 @@ static int record__synthesize(struct record *rec, bool tail)
 		goto out;
 
 	/* Synthesize id_index before auxtrace_info */
-	if (rec->opts.auxtrace_sample_mode) {
+	if (rec->opts.auxtrace_sample_mode || rec->opts.full_auxtrace) {
 		err = perf_event__synthesize_id_index(tool,
 						      process_synthesized_event,
 						      session->evlist, machine);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ac706304afe9..fe24801f8e9f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -57,6 +57,7 @@ static const char *perf_event__names[] = {
 	[PERF_RECORD_BPF_EVENT]			= "BPF_EVENT",
 	[PERF_RECORD_CGROUP]			= "CGROUP",
 	[PERF_RECORD_TEXT_POKE]			= "TEXT_POKE",
+	[PERF_RECORD_AUX_OUTPUT_HW_ID]		= "AUX_OUTPUT_HW_ID",
 	[PERF_RECORD_HEADER_ATTR]		= "ATTR",
 	[PERF_RECORD_HEADER_EVENT_TYPE]		= "EVENT_TYPE",
 	[PERF_RECORD_HEADER_TRACING_DATA]	= "TRACING_DATA",
@@ -237,6 +238,14 @@ int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused,
 	return machine__process_itrace_start_event(machine, event);
 }
 
+int perf_event__process_aux_output_hw_id(struct perf_tool *tool __maybe_unused,
+					 union perf_event *event,
+					 struct perf_sample *sample __maybe_unused,
+					 struct machine *machine)
+{
+	return machine__process_aux_output_hw_id_event(machine, event);
+}
+
 int perf_event__process_lost_samples(struct perf_tool *tool __maybe_unused,
 				     union perf_event *event,
 				     struct perf_sample *sample,
@@ -407,6 +416,12 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp)
 		       event->itrace_start.pid, event->itrace_start.tid);
 }
 
+size_t perf_event__fprintf_aux_output_hw_id(union perf_event *event, FILE *fp)
+{
+	return fprintf(fp, " hw_id: %#"PRI_lx64"\n",
+		       event->aux_output_hw_id.hw_id);
+}
+
 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp)
 {
 	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
@@ -534,6 +549,9 @@ size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FIL
 	case PERF_RECORD_TEXT_POKE:
 		ret += perf_event__fprintf_text_poke(event, machine, fp);
 		break;
+	case PERF_RECORD_AUX_OUTPUT_HW_ID:
+		ret += perf_event__fprintf_aux_output_hw_id(event, fp);
+		break;
 	default:
 		ret += fprintf(fp, "\n");
 	}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 19ad64f2bd83..95ffed66369c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -330,6 +330,10 @@ int perf_event__process_itrace_start(struct perf_tool *tool,
 				     union perf_event *event,
 				     struct perf_sample *sample,
 				     struct machine *machine);
+int perf_event__process_aux_output_hw_id(struct perf_tool *tool,
+					 union perf_event *event,
+					 struct perf_sample *sample,
+					 struct machine *machine);
 int perf_event__process_switch(struct perf_tool *tool,
 			       union perf_event *event,
 			       struct perf_sample *sample,
@@ -397,6 +401,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_aux_output_hw_id(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index da19be7da284..c6b11cd82009 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -755,6 +755,14 @@ int machine__process_itrace_start_event(struct machine *machine __maybe_unused,
 	return 0;
 }
 
+int machine__process_aux_output_hw_id_event(struct machine *machine __maybe_unused,
+					    union perf_event *event)
+{
+	if (dump_trace)
+		perf_event__fprintf_aux_output_hw_id(event, stdout);
+	return 0;
+}
+
 int machine__process_switch_event(struct machine *machine __maybe_unused,
 				  union perf_event *event)
 {
@@ -2028,6 +2036,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
 		ret = machine__process_bpf(machine, event, sample); break;
 	case PERF_RECORD_TEXT_POKE:
 		ret = machine__process_text_poke(machine, event, sample); break;
+	case PERF_RECORD_AUX_OUTPUT_HW_ID:
+		ret = machine__process_aux_output_hw_id_event(machine, event); break;
 	default:
 		ret = -1;
 		break;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 7377ed6efdf1..a143087eeb47 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -124,6 +124,8 @@ int machine__process_aux_event(struct machine *machine,
 			       union perf_event *event);
 int machine__process_itrace_start_event(struct machine *machine,
 					union perf_event *event);
+int machine__process_aux_output_hw_id_event(struct machine *machine,
+					    union perf_event *event);
 int machine__process_switch_event(struct machine *machine,
 				  union perf_event *event);
 int machine__process_namespaces_event(struct machine *machine,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 069c2cfdd3be..bdf1da9ea418 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -509,6 +509,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->bpf = perf_event__process_bpf;
 	if (tool->text_poke == NULL)
 		tool->text_poke = perf_event__process_text_poke;
+	if (tool->aux_output_hw_id == NULL)
+		tool->aux_output_hw_id = perf_event__process_aux_output_hw_id;
 	if (tool->read == NULL)
 		tool->read = process_event_sample_stub;
 	if (tool->throttle == NULL)
@@ -1000,6 +1002,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_NAMESPACES]	  = perf_event__namespaces_swap,
 	[PERF_RECORD_CGROUP]		  = perf_event__cgroup_swap,
 	[PERF_RECORD_TEXT_POKE]		  = perf_event__text_poke_swap,
+	[PERF_RECORD_AUX_OUTPUT_HW_ID]	  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_ATTR]	  = perf_event__hdr_attr_swap,
 	[PERF_RECORD_HEADER_EVENT_TYPE]	  = perf_event__event_type_swap,
 	[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
@@ -1556,6 +1559,8 @@ static int machines__deliver_event(struct machines *machines,
 		return tool->bpf(tool, event, sample, machine);
 	case PERF_RECORD_TEXT_POKE:
 		return tool->text_poke(tool, event, sample, machine);
+	case PERF_RECORD_AUX_OUTPUT_HW_ID:
+		return tool->aux_output_hw_id(tool, event, sample, machine);
 	default:
 		++evlist->stats.nr_unknown_events;
 		return -1;
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index bbbc0dcd461f..ef873f2cc38f 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -53,6 +53,7 @@ struct perf_tool {
 			lost_samples,
 			aux,
 			itrace_start,
+			aux_output_hw_id,
 			context_switch,
 			throttle,
 			unthrottle,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V3 3/3] perf intel-pt: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID
  2021-09-07 16:39 [PATCH V3 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
  2021-09-07 16:39 ` [PATCH V3 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
@ 2021-09-07 16:39 ` Adrian Hunter
  2 siblings, 0 replies; 13+ messages in thread
From: Adrian Hunter @ 2021-09-07 16:39 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
	linux-perf-users, linux-kernel

Originally, software only supported redirecting at most one PEBS event to
Intel PT (PEBS-via-PT) because it was not able to differentiate one event
from another. To overcome that, add support for the
PERF_RECORD_AUX_OUTPUT_HW_ID side-band event.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/Documentation/perf-intel-pt.txt |  7 +-
 tools/perf/util/intel-pt.c                 | 85 +++++++++++++++++++++-
 2 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/tools/perf/Documentation/perf-intel-pt.txt b/tools/perf/Documentation/perf-intel-pt.txt
index 184ba62420f0..19f792876085 100644
--- a/tools/perf/Documentation/perf-intel-pt.txt
+++ b/tools/perf/Documentation/perf-intel-pt.txt
@@ -1144,7 +1144,12 @@ Recording is selected by using the aux-output config term e.g.
 
 	perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname
 
-Note that currently, software only supports redirecting at most one PEBS event.
+Originally, software only supported redirecting at most one PEBS event because it
+was not able to differentiate one event from another. To overcome that, more recent
+kernels and perf tools add support for the PERF_RECORD_AUX_OUTPUT_HW_ID side-band event.
+To check for the presence of that event in a PEBS-via-PT trace:
+
+	perf script -D --no-itrace | grep PERF_RECORD_AUX_OUTPUT_HW_ID
 
 To display PEBS events from the Intel PT trace, use the itrace 'o' option e.g.
 
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 6f852b305e92..1073c56a512c 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -111,6 +111,7 @@ struct intel_pt {
 	u64 cbr_id;
 	u64 psb_id;
 
+	bool single_pebs;
 	bool sample_pebs;
 	struct evsel *pebs_evsel;
 
@@ -148,6 +149,14 @@ enum switch_state {
 	INTEL_PT_SS_EXPECTING_SWITCH_IP,
 };
 
+/* applicable_counters is 64-bits */
+#define INTEL_PT_MAX_PEBS 64
+
+struct intel_pt_pebs_event {
+	struct evsel *evsel;
+	u64 id;
+};
+
 struct intel_pt_queue {
 	struct intel_pt *pt;
 	unsigned int queue_nr;
@@ -189,6 +198,7 @@ struct intel_pt_queue {
 	u64 last_br_cyc_cnt;
 	unsigned int cbr_seen;
 	char insn[INTEL_PT_INSN_BUF_SZ];
+	struct intel_pt_pebs_event pebs[INTEL_PT_MAX_PEBS];
 };
 
 static void intel_pt_dump(struct intel_pt *pt __maybe_unused,
@@ -1978,15 +1988,13 @@ static void intel_pt_add_lbrs(struct branch_stack *br_stack,
 	}
 }
 
-static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
+static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evsel *evsel, u64 id)
 {
 	const struct intel_pt_blk_items *items = &ptq->state->items;
 	struct perf_sample sample = { .ip = 0, };
 	union perf_event *event = ptq->event_buf;
 	struct intel_pt *pt = ptq->pt;
-	struct evsel *evsel = pt->pebs_evsel;
 	u64 sample_type = evsel->core.attr.sample_type;
-	u64 id = evsel->core.id[0];
 	u8 cpumode;
 	u64 regs[8 * sizeof(sample.intr_regs.mask)];
 
@@ -2112,6 +2120,45 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
 	return intel_pt_deliver_synth_event(pt, event, &sample, sample_type);
 }
 
+static int intel_pt_synth_single_pebs_sample(struct intel_pt_queue *ptq)
+{
+	struct intel_pt *pt = ptq->pt;
+	struct evsel *evsel = pt->pebs_evsel;
+	u64 id = evsel->core.id[0];
+
+	return intel_pt_do_synth_pebs_sample(ptq, evsel, id);
+}
+
+static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq)
+{
+	const struct intel_pt_blk_items *items = &ptq->state->items;
+	struct intel_pt_pebs_event *pe;
+	struct intel_pt *pt = ptq->pt;
+	int err = -EINVAL;
+	int hw_id;
+
+	if (!items->has_applicable_counters || !items->applicable_counters) {
+		if (!pt->single_pebs)
+			pr_err("PEBS-via-PT record with no applicable_counters\n");
+		return intel_pt_synth_single_pebs_sample(ptq);
+	}
+
+	for_each_set_bit(hw_id, &items->applicable_counters, INTEL_PT_MAX_PEBS) {
+		pe = &ptq->pebs[hw_id];
+		if (!pe->evsel) {
+			if (!pt->single_pebs)
+				pr_err("PEBS-via-PT record with no matching event, hw_id %d\n",
+				       hw_id);
+			return intel_pt_synth_single_pebs_sample(ptq);
+		}
+		err = intel_pt_do_synth_pebs_sample(ptq, pe->evsel, pe->id);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
 static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu,
 				pid_t pid, pid_t tid, u64 ip, u64 timestamp)
 {
@@ -2882,6 +2929,30 @@ static int intel_pt_process_itrace_start(struct intel_pt *pt,
 					event->itrace_start.tid);
 }
 
+static int intel_pt_process_aux_output_hw_id(struct intel_pt *pt,
+					     union perf_event *event,
+					     struct perf_sample *sample)
+{
+	u64 hw_id = event->aux_output_hw_id.hw_id;
+	struct auxtrace_queue *queue;
+	struct intel_pt_queue *ptq;
+	struct evsel *evsel;
+
+	queue = auxtrace_queues__sample_queue(&pt->queues, sample, pt->session);
+	evsel = evlist__id2evsel_strict(pt->session->evlist, sample->id);
+	if (!queue || !queue->priv || !evsel || hw_id > INTEL_PT_MAX_PEBS) {
+		pr_err("Bad AUX output hardware ID\n");
+		return -EINVAL;
+	}
+
+	ptq = queue->priv;
+
+	ptq->pebs[hw_id].evsel = evsel;
+	ptq->pebs[hw_id].id = sample->id;
+
+	return 0;
+}
+
 static int intel_pt_find_map(struct thread *thread, u8 cpumode, u64 addr,
 			     struct addr_location *al)
 {
@@ -3009,6 +3080,8 @@ static int intel_pt_process_event(struct perf_session *session,
 		err = intel_pt_process_switch(pt, sample);
 	else if (event->header.type == PERF_RECORD_ITRACE_START)
 		err = intel_pt_process_itrace_start(pt, event, sample);
+	else if (event->header.type == PERF_RECORD_AUX_OUTPUT_HW_ID)
+		err = intel_pt_process_aux_output_hw_id(pt, event, sample);
 	else if (event->header.type == PERF_RECORD_SWITCH ||
 		 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
 		err = intel_pt_context_switch(pt, event, sample);
@@ -3393,9 +3466,13 @@ static void intel_pt_setup_pebs_events(struct intel_pt *pt)
 
 	evlist__for_each_entry(pt->session->evlist, evsel) {
 		if (evsel->core.attr.aux_output && evsel->core.id) {
+			if (pt->single_pebs) {
+				pt->single_pebs = false;
+				return;
+			}
+			pt->single_pebs = true;
 			pt->sample_pebs = true;
 			pt->pebs_evsel = evsel;
-			return;
 		}
 	}
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
@ 2021-09-07 17:45   ` Liang, Kan
  2021-09-10 16:04     ` Peter Zijlstra
  2021-10-15  9:31   ` [tip: perf/core] " tip-bot2 for Adrian Hunter
  1 sibling, 1 reply; 13+ messages in thread
From: Liang, Kan @ 2021-09-07 17:45 UTC (permalink / raw)
  To: Adrian Hunter, Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, x86, linux-perf-users,
	linux-kernel



On 9/7/2021 12:39 PM, Adrian Hunter wrote:
> PEBS-via-PT records contain a mask of applicable counters. To identify
> which event belongs to which counter, a side-band event is needed. Until
> now, there has been no side-band event, and consequently users were limited
> to using a single event.
> 
> Add such a side-band event. Note the event is optimised to output only
> when the counter index changes for an event. That works only so long as
> all PEBS-via-PT events are scheduled together, which they are for a
> recording session because they are in a single group.
> 
> Also no attribute bit is used to select the new event, so a new
> kernel is not compatible with older perf tools.  The assumption
> being that PEBS-via-PT is sufficiently esoteric that users will not
> be troubled by this.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> 
> Changes in V3:
> 	Do not set assign callback unless x86_pmu.intel_cap.pebs_output_pt_available
> 
> Changes in V2:
> 	Use callback from x86_assign_hw_event
> 
> 
>   arch/x86/events/core.c          |  6 ++++++
>   arch/x86/events/intel/core.c    | 16 ++++++++++++++++
>   arch/x86/events/perf_event.h    |  1 +
>   include/linux/perf_event.h      |  1 +
>   include/uapi/linux/perf_event.h | 15 +++++++++++++++
>   kernel/events/core.c            | 30 ++++++++++++++++++++++++++++++
>   6 files changed, 69 insertions(+)
> 
> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
> index 2a57dbed4894..be33423e9762 100644
> --- a/arch/x86/events/core.c
> +++ b/arch/x86/events/core.c
> @@ -66,6 +66,8 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_enable_all,  *x86_pmu.enable_all);
>   DEFINE_STATIC_CALL_NULL(x86_pmu_enable,	     *x86_pmu.enable);
>   DEFINE_STATIC_CALL_NULL(x86_pmu_disable,     *x86_pmu.disable);
>   
> +DEFINE_STATIC_CALL_NULL(x86_pmu_assign, *x86_pmu.assign);
> +
>   DEFINE_STATIC_CALL_NULL(x86_pmu_add,  *x86_pmu.add);
>   DEFINE_STATIC_CALL_NULL(x86_pmu_del,  *x86_pmu.del);
>   DEFINE_STATIC_CALL_NULL(x86_pmu_read, *x86_pmu.read);
> @@ -1215,6 +1217,8 @@ static inline void x86_assign_hw_event(struct perf_event *event,
>   	hwc->last_cpu = smp_processor_id();
>   	hwc->last_tag = ++cpuc->tags[i];
>   
> +	static_call_cond(x86_pmu_assign)(event, idx);
> +
>   	switch (hwc->idx) {
>   	case INTEL_PMC_IDX_FIXED_BTS:
>   	case INTEL_PMC_IDX_FIXED_VLBR:
> @@ -2005,6 +2009,8 @@ static void x86_pmu_static_call_update(void)
>   	static_call_update(x86_pmu_enable, x86_pmu.enable);
>   	static_call_update(x86_pmu_disable, x86_pmu.disable);
>   
> +	static_call_update(x86_pmu_assign, x86_pmu.assign);
> +
>   	static_call_update(x86_pmu_add, x86_pmu.add);
>   	static_call_update(x86_pmu_del, x86_pmu.del);
>   	static_call_update(x86_pmu_read, x86_pmu.read);
> diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
> index 7011e87be6d0..a555e7c2dce9 100644
> --- a/arch/x86/events/intel/core.c
> +++ b/arch/x86/events/intel/core.c
> @@ -2402,6 +2402,12 @@ static void intel_pmu_disable_event(struct perf_event *event)
>   		intel_pmu_pebs_disable(event);
>   }
>   
> +static void intel_pmu_assign_event(struct perf_event *event, int idx)
> +{
> +	if (is_pebs_pt(event))
> +		perf_report_aux_output_id(event, idx);
> +}
> +
>   static void intel_pmu_del_event(struct perf_event *event)
>   {
>   	if (needs_branch_stack(event))
> @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
>   	return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
>   }
>   
> +static void intel_aux_output_init(void)
> +{
> +	/* Refer also intel_pmu_aux_output_match() */
> +	if (x86_pmu.intel_cap.pebs_output_pt_available)
> +		x86_pmu.assign = intel_pmu_assign_event;
> +}

For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is 
always cleared. We probably need the PMU specific 
pmu->intel_cap.pebs_output_pt_available here.

> +
>   static int intel_pmu_aux_output_match(struct perf_event *event)
>   {
> +	/* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
>   	if (!x86_pmu.intel_cap.pebs_output_pt_available)
>   		return 0;
>

For a hybrid machine, this always return 0. I think we need to fix it first?

Thanks,
Kan


> @@ -6301,6 +6315,8 @@ __init int intel_pmu_init(void)
>   	if (is_hybrid())
>   		intel_pmu_check_hybrid_pmus((u64)fixed_mask);
>   
> +	intel_aux_output_init();
> +
>   	return 0;
>   }
>   
> diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
> index e3ac05c97b5e..76436a55d9ba 100644
> --- a/arch/x86/events/perf_event.h
> +++ b/arch/x86/events/perf_event.h
> @@ -726,6 +726,7 @@ struct x86_pmu {
>   	void		(*enable_all)(int added);
>   	void		(*enable)(struct perf_event *);
>   	void		(*disable)(struct perf_event *);
> +	void		(*assign)(struct perf_event *event, int idx);
>   	void		(*add)(struct perf_event *);
>   	void		(*del)(struct perf_event *);
>   	void		(*read)(struct perf_event *event);
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index fe156a8170aa..6f4a15660651 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -1398,6 +1398,7 @@ perf_event_addr_filters(struct perf_event *event)
>   }
>   
>   extern void perf_event_addr_filters_sync(struct perf_event *event);
> +extern void perf_report_aux_output_id(struct perf_event *event, u64 hw_id);
>   
>   extern int perf_output_begin(struct perf_output_handle *handle,
>   			     struct perf_sample_data *data,
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index f92880a15645..c89535de1ec8 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -1141,6 +1141,21 @@ enum perf_event_type {
>   	 */
>   	PERF_RECORD_TEXT_POKE			= 20,
>   
> +	/*
> +	 * Data written to the AUX area by hardware due to aux_output, may need
> +	 * to be matched to the event by an architecture-specific hardware ID.
> +	 * This records the hardware ID, but requires sample_id to provide the
> +	 * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT
> +	 * records from multiple events.
> +	 *
> +	 * struct {
> +	 *	struct perf_event_header	header;
> +	 *	u64				hw_id;
> +	 *	struct sample_id		sample_id;
> +	 * };
> +	 */
> +	PERF_RECORD_AUX_OUTPUT_HW_ID		= 21,
> +
>   	PERF_RECORD_MAX,			/* non-ABI */
>   };
>   
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 744e8726c5b2..79241b6e57c7 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -9073,6 +9073,36 @@ static void perf_log_itrace_start(struct perf_event *event)
>   	perf_output_end(&handle);
>   }
>   
> +void perf_report_aux_output_id(struct perf_event *event, u64 hw_id)
> +{
> +	struct perf_output_handle handle;
> +	struct perf_sample_data sample;
> +	struct perf_aux_event {
> +		struct perf_event_header        header;
> +		u64				hw_id;
> +	} rec;
> +	int ret;
> +
> +	if (event->parent)
> +		event = event->parent;
> +
> +	rec.header.type	= PERF_RECORD_AUX_OUTPUT_HW_ID;
> +	rec.header.misc	= 0;
> +	rec.header.size	= sizeof(rec);
> +	rec.hw_id	= hw_id;
> +
> +	perf_event_header__init_id(&rec.header, &sample, event);
> +	ret = perf_output_begin(&handle, &sample, event, rec.header.size);
> +
> +	if (ret)
> +		return;
> +
> +	perf_output_put(&handle, rec);
> +	perf_event__output_id_sample(event, &handle, &sample);
> +
> +	perf_output_end(&handle);
> +}
> +
>   static int
>   __perf_event_account_interrupt(struct perf_event *event, int throttle)
>   {
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-07 17:45   ` Liang, Kan
@ 2021-09-10 16:04     ` Peter Zijlstra
  2021-09-10 16:29       ` Liang, Kan
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Zijlstra @ 2021-09-10 16:04 UTC (permalink / raw)
  To: Liang, Kan
  Cc: Adrian Hunter, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Leo Yan, x86,
	linux-perf-users, linux-kernel

On Tue, Sep 07, 2021 at 01:45:22PM -0400, Liang, Kan wrote:
> On 9/7/2021 12:39 PM, Adrian Hunter wrote:

> > @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
> >   	return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
> >   }
> > +static void intel_aux_output_init(void)
> > +{
> > +	/* Refer also intel_pmu_aux_output_match() */
> > +	if (x86_pmu.intel_cap.pebs_output_pt_available)
> > +		x86_pmu.assign = intel_pmu_assign_event;
> > +}
> 
> For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is always
> cleared. We probably need the PMU specific
> pmu->intel_cap.pebs_output_pt_available here.
> 
> > +
> >   static int intel_pmu_aux_output_match(struct perf_event *event)
> >   {
> > +	/* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
> >   	if (!x86_pmu.intel_cap.pebs_output_pt_available)
> >   		return 0;
> > 
> 
> For a hybrid machine, this always return 0. I think we need to fix it first?

AFAICT the patch is correct for !hybrid, and the hybrid PT muck can then
also fix this up, right?


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-10 16:04     ` Peter Zijlstra
@ 2021-09-10 16:29       ` Liang, Kan
  2021-09-23 18:29         ` Adrian Hunter
  0 siblings, 1 reply; 13+ messages in thread
From: Liang, Kan @ 2021-09-10 16:29 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Adrian Hunter, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Leo Yan, x86,
	linux-perf-users, linux-kernel



On 9/10/2021 12:04 PM, Peter Zijlstra wrote:
> On Tue, Sep 07, 2021 at 01:45:22PM -0400, Liang, Kan wrote:
>> On 9/7/2021 12:39 PM, Adrian Hunter wrote:
> 
>>> @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
>>>    	return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
>>>    }
>>> +static void intel_aux_output_init(void)
>>> +{
>>> +	/* Refer also intel_pmu_aux_output_match() */
>>> +	if (x86_pmu.intel_cap.pebs_output_pt_available)
>>> +		x86_pmu.assign = intel_pmu_assign_event;
>>> +}
>>
>> For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is always
>> cleared. We probably need the PMU specific
>> pmu->intel_cap.pebs_output_pt_available here.
>>
>>> +
>>>    static int intel_pmu_aux_output_match(struct perf_event *event)
>>>    {
>>> +	/* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
>>>    	if (!x86_pmu.intel_cap.pebs_output_pt_available)
>>>    		return 0;
>>>
>>
>> For a hybrid machine, this always return 0. I think we need to fix it first?
> 
> AFAICT the patch is correct for !hybrid, and the hybrid PT muck can then
> also fix this up, right?
> 

Yes, for !hybrid, the patch is good.

Since PEBS via PT is temporarily disabled for hybrid for now, the patch 
set should not bring any issues with hybrid either.
The hybrid PT can be fixed separately.

Thanks,
Kan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-10 16:29       ` Liang, Kan
@ 2021-09-23 18:29         ` Adrian Hunter
  2021-09-23 19:22           ` Alexander Shishkin
  0 siblings, 1 reply; 13+ messages in thread
From: Adrian Hunter @ 2021-09-23 18:29 UTC (permalink / raw)
  To: Liang, Kan, Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Leo Yan, x86, linux-perf-users,
	linux-kernel

On 10/09/21 7:29 pm, Liang, Kan wrote:
> 
> 
> On 9/10/2021 12:04 PM, Peter Zijlstra wrote:
>> On Tue, Sep 07, 2021 at 01:45:22PM -0400, Liang, Kan wrote:
>>> On 9/7/2021 12:39 PM, Adrian Hunter wrote:
>>
>>>> @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
>>>>        return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
>>>>    }
>>>> +static void intel_aux_output_init(void)
>>>> +{
>>>> +    /* Refer also intel_pmu_aux_output_match() */
>>>> +    if (x86_pmu.intel_cap.pebs_output_pt_available)
>>>> +        x86_pmu.assign = intel_pmu_assign_event;
>>>> +}
>>>
>>> For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is always
>>> cleared. We probably need the PMU specific
>>> pmu->intel_cap.pebs_output_pt_available here.
>>>
>>>> +
>>>>    static int intel_pmu_aux_output_match(struct perf_event *event)
>>>>    {
>>>> +    /* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
>>>>        if (!x86_pmu.intel_cap.pebs_output_pt_available)
>>>>            return 0;
>>>>
>>>
>>> For a hybrid machine, this always return 0. I think we need to fix it first?
>>
>> AFAICT the patch is correct for !hybrid, and the hybrid PT muck can then
>> also fix this up, right?
>>
> 
> Yes, for !hybrid, the patch is good.
> 
> Since PEBS via PT is temporarily disabled for hybrid for now, the patch set should not bring any issues with hybrid either.
> The hybrid PT can be fixed separately.

I don't have much time to look at the hybrid case right now.

Would it be OK to go ahead with these patches?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-23 18:29         ` Adrian Hunter
@ 2021-09-23 19:22           ` Alexander Shishkin
  2021-10-13  9:12             ` Adrian Hunter
  0 siblings, 1 reply; 13+ messages in thread
From: Alexander Shishkin @ 2021-09-23 19:22 UTC (permalink / raw)
  To: Adrian Hunter, Liang, Kan, Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Jiri Olsa,
	Leo Yan, x86, linux-perf-users, linux-kernel, alexander.shishkin

Adrian Hunter <adrian.hunter@intel.com> writes:

> On 10/09/21 7:29 pm, Liang, Kan wrote:
>> 
>> 
>> On 9/10/2021 12:04 PM, Peter Zijlstra wrote:
>>> On Tue, Sep 07, 2021 at 01:45:22PM -0400, Liang, Kan wrote:
>>>> On 9/7/2021 12:39 PM, Adrian Hunter wrote:
>>>
>>>>> @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
>>>>>        return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
>>>>>    }
>>>>> +static void intel_aux_output_init(void)
>>>>> +{
>>>>> +    /* Refer also intel_pmu_aux_output_match() */
>>>>> +    if (x86_pmu.intel_cap.pebs_output_pt_available)
>>>>> +        x86_pmu.assign = intel_pmu_assign_event;
>>>>> +}
>>>>
>>>> For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is always
>>>> cleared. We probably need the PMU specific
>>>> pmu->intel_cap.pebs_output_pt_available here.
>>>>
>>>>> +
>>>>>    static int intel_pmu_aux_output_match(struct perf_event *event)
>>>>>    {
>>>>> +    /* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
>>>>>        if (!x86_pmu.intel_cap.pebs_output_pt_available)
>>>>>            return 0;
>>>>>
>>>>
>>>> For a hybrid machine, this always return 0. I think we need to fix it first?
>>>
>>> AFAICT the patch is correct for !hybrid, and the hybrid PT muck can then
>>> also fix this up, right?
>>>
>> 
>> Yes, for !hybrid, the patch is good.
>> 
>> Since PEBS via PT is temporarily disabled for hybrid for now, the patch set should not bring any issues with hybrid either.
>> The hybrid PT can be fixed separately.
>
> I don't have much time to look at the hybrid case right now.
>
> Would it be OK to go ahead with these patches?

I'll deal with the PEBS-via-PT on hybrid. As it stands right now, this
patchset is good.

Regards,
--
Alex

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-09-23 19:22           ` Alexander Shishkin
@ 2021-10-13  9:12             ` Adrian Hunter
  2021-10-13 14:17               ` Peter Zijlstra
  0 siblings, 1 reply; 13+ messages in thread
From: Adrian Hunter @ 2021-10-13  9:12 UTC (permalink / raw)
  To: Alexander Shishkin, Liang, Kan, Peter Zijlstra
  Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland, Jiri Olsa,
	Leo Yan, x86, linux-perf-users, linux-kernel

On 23/09/2021 22:22, Alexander Shishkin wrote:
> Adrian Hunter <adrian.hunter@intel.com> writes:
> 
>> On 10/09/21 7:29 pm, Liang, Kan wrote:
>>>
>>>
>>> On 9/10/2021 12:04 PM, Peter Zijlstra wrote:
>>>> On Tue, Sep 07, 2021 at 01:45:22PM -0400, Liang, Kan wrote:
>>>>> On 9/7/2021 12:39 PM, Adrian Hunter wrote:
>>>>
>>>>>> @@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
>>>>>>        return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
>>>>>>    }
>>>>>> +static void intel_aux_output_init(void)
>>>>>> +{
>>>>>> +    /* Refer also intel_pmu_aux_output_match() */
>>>>>> +    if (x86_pmu.intel_cap.pebs_output_pt_available)
>>>>>> +        x86_pmu.assign = intel_pmu_assign_event;
>>>>>> +}
>>>>>
>>>>> For a hybrid machine, x86_pmu.intel_cap.pebs_output_pt_available is always
>>>>> cleared. We probably need the PMU specific
>>>>> pmu->intel_cap.pebs_output_pt_available here.
>>>>>
>>>>>> +
>>>>>>    static int intel_pmu_aux_output_match(struct perf_event *event)
>>>>>>    {
>>>>>> +    /* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
>>>>>>        if (!x86_pmu.intel_cap.pebs_output_pt_available)
>>>>>>            return 0;
>>>>>>
>>>>>
>>>>> For a hybrid machine, this always return 0. I think we need to fix it first?
>>>>
>>>> AFAICT the patch is correct for !hybrid, and the hybrid PT muck can then
>>>> also fix this up, right?
>>>>
>>>
>>> Yes, for !hybrid, the patch is good.
>>>
>>> Since PEBS via PT is temporarily disabled for hybrid for now, the patch set should not bring any issues with hybrid either.
>>> The hybrid PT can be fixed separately.
>>
>> I don't have much time to look at the hybrid case right now.
>>
>> Would it be OK to go ahead with these patches?
> 
> I'll deal with the PEBS-via-PT on hybrid. As it stands right now, this
> patchset is good.

Will anyone takes these patches?  Perhaps Arnaldo if no one objects?
The patches still seem to apply cleanly.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-10-13  9:12             ` Adrian Hunter
@ 2021-10-13 14:17               ` Peter Zijlstra
  2021-10-13 15:34                 ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Zijlstra @ 2021-10-13 14:17 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Alexander Shishkin, Liang, Kan, Ingo Molnar,
	Arnaldo Carvalho de Melo, Mark Rutland, Jiri Olsa, Leo Yan, x86,
	linux-perf-users, linux-kernel

On Wed, Oct 13, 2021 at 12:12:48PM +0300, Adrian Hunter wrote:

> Will anyone takes these patches?  Perhaps Arnaldo if no one objects?
> The patches still seem to apply cleanly.

I've picked up the first. But if acme wants to route the whole lot:

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index
  2021-10-13 14:17               ` Peter Zijlstra
@ 2021-10-13 15:34                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-10-13 15:34 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Adrian Hunter, Alexander Shishkin, Liang, Kan, Ingo Molnar,
	Mark Rutland, Jiri Olsa, Leo Yan, x86, linux-perf-users,
	linux-kernel

Em Wed, Oct 13, 2021 at 04:17:49PM +0200, Peter Zijlstra escreveu:
> On Wed, Oct 13, 2021 at 12:12:48PM +0300, Adrian Hunter wrote:
> 
> > Will anyone takes these patches?  Perhaps Arnaldo if no one objects?
> > The patches still seem to apply cleanly.
> 
> I've picked up the first. But if acme wants to route the whole lot:
> 
> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>


I'll pick the rest, thanks.

- Arnaldo

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [tip: perf/core] perf/x86: Add new event for AUX output counter index
  2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
  2021-09-07 17:45   ` Liang, Kan
@ 2021-10-15  9:31   ` tip-bot2 for Adrian Hunter
  1 sibling, 0 replies; 13+ messages in thread
From: tip-bot2 for Adrian Hunter @ 2021-10-15  9:31 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Adrian Hunter, Peter Zijlstra (Intel), x86, linux-kernel

The following commit has been merged into the perf/core branch of tip:

Commit-ID:     8b8ff8cc3b8155c18162e8b1f70e1230db176862
Gitweb:        https://git.kernel.org/tip/8b8ff8cc3b8155c18162e8b1f70e1230db176862
Author:        Adrian Hunter <adrian.hunter@intel.com>
AuthorDate:    Tue, 07 Sep 2021 19:39:01 +03:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 15 Oct 2021 11:25:31 +02:00

perf/x86: Add new event for AUX output counter index

PEBS-via-PT records contain a mask of applicable counters. To identify
which event belongs to which counter, a side-band event is needed. Until
now, there has been no side-band event, and consequently users were limited
to using a single event.

Add such a side-band event. Note the event is optimised to output only
when the counter index changes for an event. That works only so long as
all PEBS-via-PT events are scheduled together, which they are for a
recording session because they are in a single group.

Also no attribute bit is used to select the new event, so a new
kernel is not compatible with older perf tools.  The assumption
being that PEBS-via-PT is sufficiently esoteric that users will not
be troubled by this.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20210907163903.11820-2-adrian.hunter@intel.com
---
 arch/x86/events/core.c          |  6 ++++++
 arch/x86/events/intel/core.c    | 16 ++++++++++++++++
 arch/x86/events/perf_event.h    |  1 +
 include/linux/perf_event.h      |  1 +
 include/uapi/linux/perf_event.h | 15 +++++++++++++++
 kernel/events/core.c            | 30 ++++++++++++++++++++++++++++++
 6 files changed, 69 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 2a57dbe..be33423 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -66,6 +66,8 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_enable_all,  *x86_pmu.enable_all);
 DEFINE_STATIC_CALL_NULL(x86_pmu_enable,	     *x86_pmu.enable);
 DEFINE_STATIC_CALL_NULL(x86_pmu_disable,     *x86_pmu.disable);
 
+DEFINE_STATIC_CALL_NULL(x86_pmu_assign, *x86_pmu.assign);
+
 DEFINE_STATIC_CALL_NULL(x86_pmu_add,  *x86_pmu.add);
 DEFINE_STATIC_CALL_NULL(x86_pmu_del,  *x86_pmu.del);
 DEFINE_STATIC_CALL_NULL(x86_pmu_read, *x86_pmu.read);
@@ -1215,6 +1217,8 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 	hwc->last_cpu = smp_processor_id();
 	hwc->last_tag = ++cpuc->tags[i];
 
+	static_call_cond(x86_pmu_assign)(event, idx);
+
 	switch (hwc->idx) {
 	case INTEL_PMC_IDX_FIXED_BTS:
 	case INTEL_PMC_IDX_FIXED_VLBR:
@@ -2005,6 +2009,8 @@ static void x86_pmu_static_call_update(void)
 	static_call_update(x86_pmu_enable, x86_pmu.enable);
 	static_call_update(x86_pmu_disable, x86_pmu.disable);
 
+	static_call_update(x86_pmu_assign, x86_pmu.assign);
+
 	static_call_update(x86_pmu_add, x86_pmu.add);
 	static_call_update(x86_pmu_del, x86_pmu.del);
 	static_call_update(x86_pmu_read, x86_pmu.read);
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 7011e87..a555e7c 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2402,6 +2402,12 @@ static void intel_pmu_disable_event(struct perf_event *event)
 		intel_pmu_pebs_disable(event);
 }
 
+static void intel_pmu_assign_event(struct perf_event *event, int idx)
+{
+	if (is_pebs_pt(event))
+		perf_report_aux_output_id(event, idx);
+}
+
 static void intel_pmu_del_event(struct perf_event *event)
 {
 	if (needs_branch_stack(event))
@@ -4494,8 +4500,16 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
 	return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
 }
 
+static void intel_aux_output_init(void)
+{
+	/* Refer also intel_pmu_aux_output_match() */
+	if (x86_pmu.intel_cap.pebs_output_pt_available)
+		x86_pmu.assign = intel_pmu_assign_event;
+}
+
 static int intel_pmu_aux_output_match(struct perf_event *event)
 {
+	/* intel_pmu_assign_event() is needed, refer intel_aux_output_init() */
 	if (!x86_pmu.intel_cap.pebs_output_pt_available)
 		return 0;
 
@@ -6301,6 +6315,8 @@ __init int intel_pmu_init(void)
 	if (is_hybrid())
 		intel_pmu_check_hybrid_pmus((u64)fixed_mask);
 
+	intel_aux_output_init();
+
 	return 0;
 }
 
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index e3ac05c..76436a5 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -726,6 +726,7 @@ struct x86_pmu {
 	void		(*enable_all)(int added);
 	void		(*enable)(struct perf_event *);
 	void		(*disable)(struct perf_event *);
+	void		(*assign)(struct perf_event *event, int idx);
 	void		(*add)(struct perf_event *);
 	void		(*del)(struct perf_event *);
 	void		(*read)(struct perf_event *event);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2d510ad..126b3a3 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1397,6 +1397,7 @@ perf_event_addr_filters(struct perf_event *event)
 }
 
 extern void perf_event_addr_filters_sync(struct perf_event *event);
+extern void perf_report_aux_output_id(struct perf_event *event, u64 hw_id);
 
 extern int perf_output_begin(struct perf_output_handle *handle,
 			     struct perf_sample_data *data,
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index f92880a..c89535d 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -1141,6 +1141,21 @@ enum perf_event_type {
 	 */
 	PERF_RECORD_TEXT_POKE			= 20,
 
+	/*
+	 * Data written to the AUX area by hardware due to aux_output, may need
+	 * to be matched to the event by an architecture-specific hardware ID.
+	 * This records the hardware ID, but requires sample_id to provide the
+	 * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT
+	 * records from multiple events.
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *	u64				hw_id;
+	 *	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_AUX_OUTPUT_HW_ID		= 21,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1cb1f9b..0e90a50 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9062,6 +9062,36 @@ static void perf_log_itrace_start(struct perf_event *event)
 	perf_output_end(&handle);
 }
 
+void perf_report_aux_output_id(struct perf_event *event, u64 hw_id)
+{
+	struct perf_output_handle handle;
+	struct perf_sample_data sample;
+	struct perf_aux_event {
+		struct perf_event_header        header;
+		u64				hw_id;
+	} rec;
+	int ret;
+
+	if (event->parent)
+		event = event->parent;
+
+	rec.header.type	= PERF_RECORD_AUX_OUTPUT_HW_ID;
+	rec.header.misc	= 0;
+	rec.header.size	= sizeof(rec);
+	rec.hw_id	= hw_id;
+
+	perf_event_header__init_id(&rec.header, &sample, event);
+	ret = perf_output_begin(&handle, &sample, event, rec.header.size);
+
+	if (ret)
+		return;
+
+	perf_output_put(&handle, rec);
+	perf_event__output_id_sample(event, &handle, &sample);
+
+	perf_output_end(&handle);
+}
+
 static int
 __perf_event_account_interrupt(struct perf_event *event, int throttle)
 {

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-10-15  9:32 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-07 16:39 [PATCH V3 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
2021-09-07 16:39 ` [PATCH V3 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
2021-09-07 17:45   ` Liang, Kan
2021-09-10 16:04     ` Peter Zijlstra
2021-09-10 16:29       ` Liang, Kan
2021-09-23 18:29         ` Adrian Hunter
2021-09-23 19:22           ` Alexander Shishkin
2021-10-13  9:12             ` Adrian Hunter
2021-10-13 14:17               ` Peter Zijlstra
2021-10-13 15:34                 ` Arnaldo Carvalho de Melo
2021-10-15  9:31   ` [tip: perf/core] " tip-bot2 for Adrian Hunter
2021-09-07 16:39 ` [PATCH V3 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
2021-09-07 16:39 ` [PATCH V3 3/3] perf intel-pt: " Adrian Hunter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.