* [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band
@ 2021-06-09 14:20 Adrian Hunter
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Adrian Hunter @ 2021-06-09 14:20 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.
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 | 1 +
arch/x86/events/intel/ds.c | 16 ++++++
include/linux/perf_event.h | 2 +
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 +
17 files changed, 217 insertions(+), 7 deletions(-)
Regards
Adrian
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/3] perf/x86: Add new event for AUX output counter index
2021-06-09 14:20 [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
@ 2021-06-09 14:20 ` Adrian Hunter
2021-06-25 12:06 ` Peter Zijlstra
2021-06-25 13:15 ` Peter Zijlstra
2021-06-09 14:20 ` [PATCH 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
` (2 subsequent siblings)
3 siblings, 2 replies; 9+ messages in thread
From: Adrian Hunter @ 2021-06-09 14:20 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>
Reviewed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
---
arch/x86/events/core.c | 1 +
arch/x86/events/intel/ds.c | 16 ++++++++++++++++
include/linux/perf_event.h | 2 ++
include/uapi/linux/perf_event.h | 15 +++++++++++++++
kernel/events/core.c | 30 ++++++++++++++++++++++++++++++
5 files changed, 64 insertions(+)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 8f71dd72ef95..30d0d18eb4b6 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -660,6 +660,7 @@ static int __x86_pmu_event_init(struct perf_event *event)
event->destroy = hw_perf_event_destroy;
event->hw.idx = -1;
+ event->hw.idx_reported = -1;
event->hw.last_cpu = -1;
event->hw.last_tag = ~0ULL;
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 1ec8fd311f38..d4c149b6e82b 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -1182,6 +1182,20 @@ static void intel_pmu_pebs_via_pt_disable(struct perf_event *event)
cpuc->pebs_enabled &= ~PEBS_VIA_PT_MASK;
}
+static void intel_pmu_report_aux_output_id(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ /*
+ * So long as all PEBS-via-PT events for a recording session are
+ * scheduled together, then only changes to hwc->idx need be reported.
+ */
+ if (hwc->idx != hwc->idx_reported) {
+ hwc->idx_reported = hwc->idx;
+ perf_report_aux_output_id(event, hwc->idx);
+ }
+}
+
static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -1191,6 +1205,8 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
if (!is_pebs_pt(event))
return;
+ intel_pmu_report_aux_output_id(event);
+
if (!(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS))
cpuc->pebs_enabled |= PEBS_PMI_AFTER_EACH_RECORD;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index f5a6a2f069ed..18bfa05537ab 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -141,6 +141,7 @@ struct hw_perf_event {
unsigned long event_base;
int event_base_rdpmc;
int idx;
+ int idx_reported;
int last_cpu;
int flags;
@@ -1397,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 6fee4a7e88d7..bf98c8932ae2 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9055,6 +9055,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] 9+ messages in thread
* [PATCH 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID
2021-06-09 14:20 [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
@ 2021-06-09 14:20 ` Adrian Hunter
2021-06-09 14:20 ` [PATCH 3/3] perf intel-pt: " Adrian Hunter
2021-06-21 6:15 ` [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
3 siblings, 0 replies; 9+ messages in thread
From: Adrian Hunter @ 2021-06-09 14:20 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 4d0c02ba3f7d..75ee385fb078 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 5d6f583e2cd3..8d7a0a0a4cb2 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -813,7 +813,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 */
@@ -880,6 +881,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 bc3dd379eb67..95f93e0799d3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1437,7 +1437,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 3ff4936a15a4..dad2e89095d7 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)
{
@@ -2027,6 +2035,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 0dbb4f2628f3..9ec78dea118d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -504,6 +504,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)
@@ -995,6 +997,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,
@@ -1549,6 +1552,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] 9+ messages in thread
* [PATCH 3/3] perf intel-pt: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID
2021-06-09 14:20 [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
2021-06-09 14:20 ` [PATCH 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
@ 2021-06-09 14:20 ` Adrian Hunter
2021-06-21 6:15 ` [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
3 siblings, 0 replies; 9+ messages in thread
From: Adrian Hunter @ 2021-06-09 14:20 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 154a1077f22e..9e0539d3a79c 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;
@@ -147,6 +148,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;
@@ -188,6 +197,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,
@@ -1976,15 +1986,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)];
@@ -2110,6 +2118,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)
{
@@ -2880,6 +2927,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)
{
@@ -3007,6 +3078,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);
@@ -3391,9 +3464,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] 9+ messages in thread
* Re: [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band
2021-06-09 14:20 [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
` (2 preceding siblings ...)
2021-06-09 14:20 ` [PATCH 3/3] perf intel-pt: " Adrian Hunter
@ 2021-06-21 6:15 ` Adrian Hunter
3 siblings, 0 replies; 9+ messages in thread
From: Adrian Hunter @ 2021-06-21 6:15 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
On 9/06/21 5:20 pm, Adrian Hunter wrote:
> 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.
Any comments on this patch set?
>
> 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.
>
>
> 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 | 1 +
> arch/x86/events/intel/ds.c | 16 ++++++
> include/linux/perf_event.h | 2 +
> 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 +
> 17 files changed, 217 insertions(+), 7 deletions(-)
>
>
> Regards
> Adrian
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] perf/x86: Add new event for AUX output counter index
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
@ 2021-06-25 12:06 ` Peter Zijlstra
2021-06-25 13:15 ` Peter Zijlstra
1 sibling, 0 replies; 9+ messages in thread
From: Peter Zijlstra @ 2021-06-25 12:06 UTC (permalink / raw)
To: Adrian Hunter
Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
linux-perf-users, linux-kernel
On Wed, Jun 09, 2021 at 05:20:53PM +0300, Adrian Hunter wrote:
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index f5a6a2f069ed..18bfa05537ab 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -141,6 +141,7 @@ struct hw_perf_event {
> unsigned long event_base;
> int event_base_rdpmc;
> int idx;
> + int idx_reported;
> int last_cpu;
> int flags;
>
This is sad, it blows up the largest element in that union from 96 to
104 bytes.
Is there really no better place for this?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] perf/x86: Add new event for AUX output counter index
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
2021-06-25 12:06 ` Peter Zijlstra
@ 2021-06-25 13:15 ` Peter Zijlstra
2021-06-30 9:21 ` Adrian Hunter
1 sibling, 1 reply; 9+ messages in thread
From: Peter Zijlstra @ 2021-06-25 13:15 UTC (permalink / raw)
To: Adrian Hunter
Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
linux-perf-users, linux-kernel
On Wed, Jun 09, 2021 at 05:20:53PM +0300, Adrian Hunter wrote:
> +static void intel_pmu_report_aux_output_id(struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> +
> + /*
> + * So long as all PEBS-via-PT events for a recording session are
> + * scheduled together, then only changes to hwc->idx need be reported.
> + */
> + if (hwc->idx != hwc->idx_reported) {
> + hwc->idx_reported = hwc->idx;
> + perf_report_aux_output_id(event, hwc->idx);
> + }
> +}
AFAICT you want a callback in x86_assign_hw_event(), is that so?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] perf/x86: Add new event for AUX output counter index
2021-06-25 13:15 ` Peter Zijlstra
@ 2021-06-30 9:21 ` Adrian Hunter
2021-06-30 11:04 ` Peter Zijlstra
0 siblings, 1 reply; 9+ messages in thread
From: Adrian Hunter @ 2021-06-30 9:21 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
On 25/06/21 4:15 pm, Peter Zijlstra wrote:
> On Wed, Jun 09, 2021 at 05:20:53PM +0300, Adrian Hunter wrote:
>
>> +static void intel_pmu_report_aux_output_id(struct perf_event *event)
>> +{
>> + struct hw_perf_event *hwc = &event->hw;
>> +
>> + /*
>> + * So long as all PEBS-via-PT events for a recording session are
>> + * scheduled together, then only changes to hwc->idx need be reported.
>> + */
>> + if (hwc->idx != hwc->idx_reported) {
>> + hwc->idx_reported = hwc->idx;
>> + perf_report_aux_output_id(event, hwc->idx);
>> + }
>> +}
>
> AFAICT you want a callback in x86_assign_hw_event(), is that so?
>
Yes, or open-coded e.g.
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 8f71dd72ef95..46dac45298d1 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -1207,6 +1207,11 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader,
return n;
}
+static inline bool report_aux_output_id(struct perf_event *event)
+{
+ return is_pebs_pt(event);
+}
+
static inline void x86_assign_hw_event(struct perf_event *event,
struct cpu_hw_events *cpuc, int i)
{
@@ -1217,6 +1222,9 @@ static inline void x86_assign_hw_event(struct perf_event *event,
hwc->last_cpu = smp_processor_id();
hwc->last_tag = ++cpuc->tags[i];
+ if (report_aux_output_id(event))
+ perf_report_aux_output_id(event, idx);
+
switch (hwc->idx) {
case INTEL_PMC_IDX_FIXED_BTS:
case INTEL_PMC_IDX_FIXED_VLBR:
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] perf/x86: Add new event for AUX output counter index
2021-06-30 9:21 ` Adrian Hunter
@ 2021-06-30 11:04 ` Peter Zijlstra
0 siblings, 0 replies; 9+ messages in thread
From: Peter Zijlstra @ 2021-06-30 11:04 UTC (permalink / raw)
To: Adrian Hunter
Cc: Ingo Molnar, Arnaldo Carvalho de Melo, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Leo Yan, Kan Liang, x86,
linux-perf-users, linux-kernel
On Wed, Jun 30, 2021 at 12:21:07PM +0300, Adrian Hunter wrote:
> On 25/06/21 4:15 pm, Peter Zijlstra wrote:
> > On Wed, Jun 09, 2021 at 05:20:53PM +0300, Adrian Hunter wrote:
> >
> >> +static void intel_pmu_report_aux_output_id(struct perf_event *event)
> >> +{
> >> + struct hw_perf_event *hwc = &event->hw;
> >> +
> >> + /*
> >> + * So long as all PEBS-via-PT events for a recording session are
> >> + * scheduled together, then only changes to hwc->idx need be reported.
> >> + */
> >> + if (hwc->idx != hwc->idx_reported) {
> >> + hwc->idx_reported = hwc->idx;
> >> + perf_report_aux_output_id(event, hwc->idx);
> >> + }
> >> +}
> >
> > AFAICT you want a callback in x86_assign_hw_event(), is that so?
> >
>
> Yes, or open-coded e.g.
>
> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
> index 8f71dd72ef95..46dac45298d1 100644
> --- a/arch/x86/events/core.c
> +++ b/arch/x86/events/core.c
> @@ -1207,6 +1207,11 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader,
> return n;
> }
>
> +static inline bool report_aux_output_id(struct perf_event *event)
> +{
> + return is_pebs_pt(event);
> +}
> +
> static inline void x86_assign_hw_event(struct perf_event *event,
> struct cpu_hw_events *cpuc, int i)
> {
> @@ -1217,6 +1222,9 @@ static inline void x86_assign_hw_event(struct perf_event *event,
> hwc->last_cpu = smp_processor_id();
> hwc->last_tag = ++cpuc->tags[i];
>
> + if (report_aux_output_id(event))
> + perf_report_aux_output_id(event, idx);
> +
> switch (hwc->idx) {
> case INTEL_PMC_IDX_FIXED_BTS:
> case INTEL_PMC_IDX_FIXED_VLBR:
Right, bit yuck, but I suppose it works. The alternative is something
like:
static_call_cond(x86_pmu_assign)(event, idx);
but I'm not sure that's worth it, but it avoids stuffing even more intel
specific bits into the core.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2021-06-30 11:05 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-09 14:20 [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
2021-06-09 14:20 ` [PATCH 1/3] perf/x86: Add new event for AUX output counter index Adrian Hunter
2021-06-25 12:06 ` Peter Zijlstra
2021-06-25 13:15 ` Peter Zijlstra
2021-06-30 9:21 ` Adrian Hunter
2021-06-30 11:04 ` Peter Zijlstra
2021-06-09 14:20 ` [PATCH 2/3] perf tools: Add support for PERF_RECORD_AUX_OUTPUT_HW_ID Adrian Hunter
2021-06-09 14:20 ` [PATCH 3/3] perf intel-pt: " Adrian Hunter
2021-06-21 6:15 ` [PATCH 0/3] perf intel-pt: Add PEBS-via-PT side-band Adrian Hunter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).