* [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via
@ 2025-09-15 7:27 Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc Athira Rajeev
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
The pseries Shared Processor Logical Partition(SPLPAR) machines can
retrieve a log of dispatch and preempt events from the hypervisor
using data from Disptach Trace Log(DTL) buffer. With this information,
user can retrieve when and why each dispatch & preempt has occurred.
The vpa-dtl PMU exposes the Virtual Processor Area(VPA) DTL counters
via perf.
- Patch 1 to 6 is perf tools side code changes to enable perf
report/script on perf.data file
Kernel and tools patches is separated. Kernel patches are posted here :
https://lore.kernel.org/linux-perf-users/20250915072224.98958-1-atrajeev@linux.ibm.com/T/#t
Infrastructure used
===================
The VPA DTL PMU counters do not interrupt on overflow or generate any
PMI interrupts. Therefore, hrtimer is used to poll the DTL data. The timer
nterval can be provided by user via sample_period field in nano seconds.
vpa dtl pmu has one hrtimer added per vpa-dtl pmu thread. DTL (Dispatch
Trace Log) contains information about dispatch/preempt, enqueue time etc.
We directly copy the DTL buffer data as part of auxiliary buffer and it
will be processed later. This will avoid time taken to create samples
in the kernel space. The PMU driver collecting Dispatch Trace Log (DTL)
entries makes use of AUX support in perf infrastructure. On the tools side,
this data is made available as PERF_RECORD_AUXTRACE records.
To corelate each DTL entry with other events across CPU's, an auxtrace_queue
is created for each CPU. Each auxtrace queue has a array/list of auxtrace buffers.
All auxtrace queues is maintained in auxtrace heap. The queues are sorted
based on timestamp. When the different PERF_RECORD_XX records are processed,
compare the timestamp of perf record with timestamp of top element in the
auxtrace heap so that DTL events can be co-related with other events
Process the auxtrace queue if the timestamp of element from heap is
lower than timestamp from entry in perf record. Sometimes it could happen that
one buffer is only partially processed. if the timestamp of occurrence of
another event is more than currently processed element in the queue, it will
move on to next perf record. So keep track of position of buffer to continue
processing next time. Update the timestamp of the auxtrace heap with the timestamp
of last processed entry from the auxtrace buffer.
This infrastructure ensures dispatch trace log entries can be corelated
and presented along with other events like sched.
vpa-dtl PMU example usage
# ls /sys/devices/vpa_dtl/
events format perf_event_mux_interval_ms power subsystem type uevent
To capture the DTL data using perf record:
# ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
The result can be interpreted using perf report. Snippet of perf report -D:
# ./perf report -D
There are different PERF_RECORD_XX records. In that records corresponding to
auxtrace buffers includes:
1. PERF_RECORD_AUX
Conveys that new data is available in AUX area
2. PERF_RECORD_AUXTRACE_INFO
Describes offset and size of auxtrace data in the buffers
3. PERF_RECORD_AUXTRACE
This is the record that defines the auxtrace data which here in case of
vpa-dtl pmu is dispatch trace log data.
Snippet from perf report -D showing the PERF_RECORD_AUXTRACE dump
0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
.
. ... VPA DTL PMU data: size 1680 bytes, entries is 35
. 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
. 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
. 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
. 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
. 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
. 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
. 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
. 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
. 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
Above is representation of dtl entry of below format:
struct dtl_entry {
u8 dispatch_reason;
u8 preempt_reason;
u16 processor_id;
u32 enqueue_to_dispatch_time;
u32 ready_to_enqueue_time;
u32 waiting_to_ready_time;
u64 timebase;
u64 fault_addr;
u64 srr0;
u64 srr1;
};
First two fields represent the dispatch reason and preempt reason. The post
procecssing of PERF_RECORD_AUXTRACE records will translate to meaninful data
for user to consume.
Visualize the dispatch trace log entries with perf report:
# ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.300 MB perf.data ]
# ./perf report
# Samples: 321 of event 'vpa-dtl'
# Event count (approx.): 321
#
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ..............................
#
100.00% 100.00% swapper [kernel.kallsyms] [k] plpar_hcall_norets_notrace
Visualize the dispatch trace log entries with perf script:
# ./perf script
perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
Thanks
Athira
Athira Rajeev (6):
tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
tools/perf: process auxtrace events and display in perf report -D
tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to
present DTL samples
tools/perf: Allocate and setup aux buffer queue to help co-relate with
other events across CPU's
tools/perf: Process the DTL entries in queue and deliver samples
tools/perf: Enable perf script to present the DTL entries
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++
tools/perf/builtin-script.c | 27 +
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 4 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/event.h | 20 +
tools/perf/util/powerpc-vpadtl.c | 732 ++++++++++++++++++++++++
tools/perf/util/powerpc-vpadtl.h | 25 +
9 files changed, 925 insertions(+)
create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
create mode 100644 tools/perf/util/powerpc-vpadtl.c
create mode 100644 tools/perf/util/powerpc-vpadtl.h
--
2.47.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 15:07 ` Adrian Hunter
2025-09-15 7:27 ` [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D Athira Rajeev
` (5 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
The powerpc PMU collecting Dispatch Trace Log (DTL) entries makes use of
AUX support in perf infrastructure. The PMU driver has the functionality
to collect trace entries in the aux buffer. On the tools side, this data
is made available as PERF_RECORD_AUXTRACE records. This record is
generated by "perf record" command. To enable the creation of
PERF_RECORD_AUXTRACE, add functions to initialize auxtrace records ie
"auxtrace_record__init()". Fill in fields for other callbacks like
info_priv_size, info_fill, free, recording options etc. Define
auxtrace_type as PERF_AUXTRACE_VPA_DTL. Add header file to define vpa
dtl pmu specific details.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changelog:
Addressed review comments from Adrian:
- Return VPADTL_AUXTRACE_PRIV_SIZE in powerpc_vpadtl_info_priv_size
- Remove unused powerpc_vpadtl_parse_snapshot_options
- Some of the function parameters had "__maybe_unused", corrected it.
- Used PERF_AUXTRACE_VPA_DTL instead of PERF_AUXTRACE_VPA_PMU
- Moved powerpc_vpadtl_process_auxtrace_info to next patch
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++++++++++++++++++++++
tools/perf/util/auxtrace.c | 1 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/powerpc-vpadtl.h | 18 ++++
5 files changed, 135 insertions(+)
create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
create mode 100644 tools/perf/util/powerpc-vpadtl.h
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index fdd6a77a3432..a5b0babd307e 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -10,3 +10,4 @@ perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+perf-util-$(CONFIG_AUXTRACE) += auxtrace.o
diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
new file mode 100644
index 000000000000..803c582c0c6f
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VPA support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/string.h>
+#include <time.h>
+
+#include "../../util/cpumap.h"
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/session.h"
+#include "../../util/util.h"
+#include "../../util/pmu.h"
+#include "../../util/debug.h"
+#include "../../util/auxtrace.h"
+#include "../../util/powerpc-vpadtl.h"
+#include "../../util/record.h"
+#include <internal/lib.h> // page_size
+
+#define KiB(x) ((x) * 1024)
+
+static int
+powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
+ struct evlist *evlist __maybe_unused,
+ struct record_opts *opts)
+{
+ opts->full_auxtrace = true;
+
+ /*
+ * Set auxtrace_mmap_pages to minimum
+ * two pages
+ */
+ if (!opts->auxtrace_mmap_pages) {
+ opts->auxtrace_mmap_pages = KiB(128) / page_size;
+ if (opts->mmap_pages == UINT_MAX)
+ opts->mmap_pages = KiB(256) / page_size;
+ }
+
+ return 0;
+}
+
+static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct evlist *evlist __maybe_unused)
+{
+ return VPADTL_AUXTRACE_PRIV_SIZE;
+}
+
+static int
+powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused,
+ struct perf_record_auxtrace_info *auxtrace_info,
+ size_t priv_size __maybe_unused)
+{
+ auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
+
+ return 0;
+}
+
+static void powerpc_vpadtl_free(struct auxtrace_record *itr)
+{
+ free(itr);
+}
+
+static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
+{
+ return 0;
+}
+
+struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
+ int *err)
+{
+ struct auxtrace_record *aux;
+ struct evsel *pos;
+ char *pmu_name;
+ int found = 0;
+
+ evlist__for_each_entry(evlist, pos) {
+ pmu_name = strdup(pos->name);
+ pmu_name = strtok(pmu_name, "/");
+ if (strstarts(pmu_name, "vpa_dtl")) {
+ found = 1;
+ pos->needs_auxtrace_mmap = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ /*
+ * To obtain the auxtrace buffer file descriptor, the auxtrace event
+ * must come first.
+ */
+ evlist__to_front(pos->evlist, pos);
+
+ aux = zalloc(sizeof(*aux));
+ if (aux == NULL) {
+ pr_debug("aux record is NULL\n");
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ aux->recording_options = powerpc_vpadtl_recording_options;
+ aux->info_priv_size = powerpc_vpadtl_info_priv_size;
+ aux->info_fill = powerpc_vpadtl_info_fill;
+ aux->free = powerpc_vpadtl_free;
+ aux->reference = powerpc_vpadtl_reference;
+ return aux;
+}
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index ebd32f1b8f12..f294658bb948 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -1393,6 +1393,7 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
case PERF_AUXTRACE_HISI_PTT:
err = hisi_ptt_process_auxtrace_info(event, session);
break;
+ case PERF_AUXTRACE_VPA_DTL:
case PERF_AUXTRACE_UNKNOWN:
default:
return -EINVAL;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index f001cbb68f8e..e0a5b39fed12 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -50,6 +50,7 @@ enum auxtrace_type {
PERF_AUXTRACE_ARM_SPE,
PERF_AUXTRACE_S390_CPUMSF,
PERF_AUXTRACE_HISI_PTT,
+ PERF_AUXTRACE_VPA_DTL,
};
enum itrace_period_type {
diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
new file mode 100644
index 000000000000..50a7aa24acbe
--- /dev/null
+++ b/tools/perf/util/powerpc-vpadtl.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * VPA DTL PMU Support
+ */
+
+#ifndef INCLUDE__PERF_POWERPC_VPADTL_H__
+#define INCLUDE__PERF_POWERPC_VPADTL_H__
+
+#define POWERPC_VPADTL_NAME "powerpc_vpadtl_"
+
+enum {
+ POWERPC_VPADTL_TYPE,
+ VPADTL_AUXTRACE_PRIV_MAX,
+};
+
+#define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
+
+#endif
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-15 7:27 ` [PATCH V2 3/6] tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to present DTL samples Athira Rajeev
` (4 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
Add vpa dtl pmu auxtrace process function for "perf report -D".
The auxtrace event processing functions are defined in file
"util/powerpc-vpadtl.c". Data structures used includes "struct
powerpc_vpadtl_queue", "struct powerpc_vpadtl" to store the auxtrace
buffers in queue. Different PERF_RECORD_XXX are generated
during recording. PERF_RECORD_AUXTRACE_INFO is processed first
since it is of type perf_user_event_type and perf session event
delivers perf_session__process_user_event() first. Define function
powerpc_vpadtl_process_auxtrace_info() to handle the processing of
PERF_RECORD_AUXTRACE_INFO records. In this function, initialize
the aux buffer queues using auxtrace_queues__init(). Setup the
required infrastructure for aux data processing. The data is collected
per CPU and auxtrace_queue is created for each CPU.
Define powerpc_vpadtl_process_event() function to process
PERF_RECORD_AUXTRACE records. In this, add the event to queue using
auxtrace_queues__add_event() and process the buffer in
powerpc_vpadtl_dump_event(). The first entry in the buffer with
timebase as zero has boot timebase and frequency. Remaining data is of
format for "struct powerpc_vpadtl_entry". Define the translation for
dispatch_reasons and preempt_reasons, report this when dump trace is
invoked via powerpc_vpadtl_dump()
Sample output:
./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.300 MB perf.data ]
./perf report -D
0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
.
. ... VPA DTL PMU data: size 1680 bytes, entries is 35
. 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
. 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
. 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
. 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
. 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
. 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
. 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
. 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
. 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changelog:
Addressed review comments from Adrian
- Renamed dtl_entry to powerpc_vpadtl_entry in util/event.h
- Removed unused #includes in powerpc-vpadtl.c
- Added helper session_to_vpa to get "struct powerpc_vpadtl"
- Updated auxtrace_queues__add_event only for piped data
- Used zfree to free "struct powerpc_vpadtl_queue"
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 3 +
tools/perf/util/event.h | 16 ++
tools/perf/util/powerpc-vpadtl.c | 263 +++++++++++++++++++++++++++++++
tools/perf/util/powerpc-vpadtl.h | 7 +
5 files changed, 290 insertions(+)
create mode 100644 tools/perf/util/powerpc-vpadtl.c
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 4959e7a990e4..5ead46dc98e7 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -136,6 +136,7 @@ perf-util-$(CONFIG_AUXTRACE) += arm-spe-decoder/
perf-util-$(CONFIG_AUXTRACE) += hisi-ptt.o
perf-util-$(CONFIG_AUXTRACE) += hisi-ptt-decoder/
perf-util-$(CONFIG_AUXTRACE) += s390-cpumsf.o
+perf-util-$(CONFIG_AUXTRACE) += powerpc-vpadtl.o
ifdef CONFIG_LIBOPENCSD
perf-util-$(CONFIG_AUXTRACE) += cs-etm.o
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index f294658bb948..6d10f3d61ff8 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -55,6 +55,7 @@
#include "hisi-ptt.h"
#include "s390-cpumsf.h"
#include "util/mmap.h"
+#include "powerpc-vpadtl.h"
#include <linux/ctype.h>
#include "symbol/kallsyms.h"
@@ -1394,6 +1395,8 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
err = hisi_ptt_process_auxtrace_info(event, session);
break;
case PERF_AUXTRACE_VPA_DTL:
+ err = powerpc_vpadtl_process_auxtrace_info(event, session);
+ break;
case PERF_AUXTRACE_UNKNOWN:
default:
return -EINVAL;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index e40d16d3246c..7ba208ae86fd 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -254,6 +254,22 @@ struct perf_synth_intel_iflag_chg {
u64 branch_ip; /* If via_branch */
};
+/*
+ * The powerpc VPA DTL entries are of below format
+ */
+struct powerpc_vpadtl_entry {
+ u8 dispatch_reason;
+ u8 preempt_reason;
+ u16 processor_id;
+ u32 enqueue_to_dispatch_time;
+ u32 ready_to_enqueue_time;
+ u32 waiting_to_ready_time;
+ u64 timebase;
+ u64 fault_addr;
+ u64 srr0;
+ u64 srr1;
+};
+
static inline void *perf_synth__raw_data(void *p)
{
return p + 4;
diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
new file mode 100644
index 000000000000..2e8488a3dbd7
--- /dev/null
+++ b/tools/perf/util/powerpc-vpadtl.c
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VPA DTL PMU support
+ */
+
+#include <inttypes.h>
+#include "color.h"
+#include "evlist.h"
+#include "session.h"
+#include "debug.h"
+#include "powerpc-vpadtl.h"
+
+/*
+ * Structure to save the auxtrace queue
+ */
+struct powerpc_vpadtl {
+ struct auxtrace auxtrace;
+ struct auxtrace_queues queues;
+ struct auxtrace_heap heap;
+ u32 auxtrace_type;
+ struct perf_session *session;
+ struct machine *machine;
+ u32 pmu_type;
+};
+
+struct boottb_freq {
+ u64 boot_tb;
+ u64 tb_freq;
+ u64 timebase;
+ u64 padded[3];
+};
+
+struct powerpc_vpadtl_queue {
+ struct powerpc_vpadtl *vpa;
+ unsigned int queue_nr;
+ struct auxtrace_buffer *buffer;
+ struct thread *thread;
+ bool on_heap;
+ bool done;
+ pid_t pid;
+ pid_t tid;
+ int cpu;
+};
+
+const char *dispatch_reasons[11] = {
+ "external_interrupt",
+ "firmware_internal_event",
+ "H_PROD",
+ "decrementer_interrupt",
+ "system_reset",
+ "firmware_internal_event",
+ "conferred_cycles",
+ "time_slice",
+ "virtual_memory_page_fault",
+ "expropriated_adjunct",
+ "priv_doorbell"};
+
+const char *preempt_reasons[10] = {
+ "unused",
+ "firmware_internal_event",
+ "H_CEDE",
+ "H_CONFER",
+ "time_slice",
+ "migration_hibernation_page_fault",
+ "virtual_memory_page_fault",
+ "H_CONFER_ADJUNCT",
+ "hcall_adjunct",
+ "HDEC_adjunct"};
+
+#define dtl_entry_size sizeof(struct powerpc_vpadtl_entry)
+
+/*
+ * Function to dump the dispatch trace data when perf report
+ * is invoked with -D
+ */
+static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
+ unsigned char *buf, size_t len)
+{
+ struct powerpc_vpadtl_entry *dtl;
+ int pkt_len, pos = 0;
+ const char *color = PERF_COLOR_BLUE;
+
+ color_fprintf(stdout, color,
+ ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n",
+ len, len/dtl_entry_size);
+
+ if (len % dtl_entry_size)
+ len = len - (len % dtl_entry_size);
+
+ while (len) {
+ pkt_len = dtl_entry_size;
+ printf(".");
+ color_fprintf(stdout, color, " %08x: ", pos);
+ dtl = (struct powerpc_vpadtl_entry *)buf;
+ if (dtl->timebase != 0) {
+ printf("dispatch_reason:%s, preempt_reason:%s, enqueue_to_dispatch_time:%d,"
+ "ready_to_enqueue_time:%d, waiting_to_ready_time:%d\n",
+ dispatch_reasons[dtl->dispatch_reason], preempt_reasons[dtl->preempt_reason],\
+ be32_to_cpu(dtl->enqueue_to_dispatch_time),\
+ be32_to_cpu(dtl->ready_to_enqueue_time), be32_to_cpu(dtl->waiting_to_ready_time));
+ } else {
+ struct boottb_freq *boot_tb = (struct boottb_freq *)buf;
+
+ printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n", boot_tb->boot_tb, boot_tb->tb_freq);
+ }
+
+ pos += pkt_len;
+ buf += pkt_len;
+ len -= pkt_len;
+ }
+}
+
+static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
+{
+ return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
+}
+
+static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf,
+ size_t len)
+{
+ printf(".\n");
+ powerpc_vpadtl_dump(vpa, buf, len);
+}
+
+static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ const struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+/*
+ * Process PERF_RECORD_AUXTRACE records
+ */
+static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session,
+ union perf_event *event,
+ const struct perf_tool *tool __maybe_unused)
+{
+ struct powerpc_vpadtl *vpa = session_to_vpa(session);
+ struct auxtrace_buffer *buffer;
+ int fd = perf_data__fd(session->data);
+ off_t data_offset;
+ int err;
+
+ if (!dump_trace)
+ return 0;
+
+ if (perf_data__is_pipe(session->data)) {
+ data_offset = 0;
+ } else {
+ data_offset = lseek(fd, 0, SEEK_CUR);
+ if (data_offset == -1)
+ return -errno;
+ }
+
+ err = auxtrace_queues__add_event(&vpa->queues, session, event,
+ data_offset, &buffer);
+
+ if (err)
+ return err;
+
+ /* Dump here now we have copied a piped trace out of the pipe */
+ if (auxtrace_buffer__get_data(buffer, fd)) {
+ powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size);
+ auxtrace_buffer__put_data(buffer);
+ }
+
+ return 0;
+}
+
+static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused,
+ const struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static void powerpc_vpadtl_free_events(struct perf_session *session)
+{
+ struct powerpc_vpadtl *vpa = session_to_vpa(session);
+ struct auxtrace_queues *queues = &vpa->queues;
+ struct powerpc_vpadtl_queue *vpaq;
+
+ unsigned int i;
+
+ for (i = 0; i < queues->nr_queues; i++) {
+ vpaq = queues->queue_array[i].priv;
+ if (vpaq)
+ zfree(&vpaq);
+ }
+
+ auxtrace_queues__free(queues);
+}
+
+static void powerpc_vpadtl_free(struct perf_session *session)
+{
+ struct powerpc_vpadtl *vpa = session_to_vpa(session);
+
+ auxtrace_heap__free(&vpa->heap);
+ powerpc_vpadtl_free_events(session);
+ session->auxtrace = NULL;
+ free(vpa);
+}
+
+static const char * const powerpc_vpadtl_info_fmts[] = {
+ [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n",
+};
+
+static void powerpc_vpadtl_print_info(__u64 *arr)
+{
+ if (!dump_trace)
+ return;
+
+ fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]);
+}
+
+/*
+ * Process the PERF_RECORD_AUXTRACE_INFO records and setup
+ * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO
+ * is processed first since it is of type perf_user_event_type.
+ * Initialise the aux buffer queues using auxtrace_queues__init().
+ * auxtrace_queue is created for each CPU.
+ */
+int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session)
+{
+ struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
+ size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE;
+ struct powerpc_vpadtl *vpa;
+ int err;
+
+ if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
+ min_sz)
+ return -EINVAL;
+
+ vpa = zalloc(sizeof(struct powerpc_vpadtl));
+ if (!vpa)
+ return -ENOMEM;
+
+ err = auxtrace_queues__init(&vpa->queues);
+ if (err)
+ goto err_free;
+
+ vpa->session = session;
+ vpa->machine = &session->machines.host; /* No kvm support */
+ vpa->auxtrace_type = auxtrace_info->type;
+ vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE];
+
+ vpa->auxtrace.process_event = powerpc_vpadtl_process_event;
+ vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event;
+ vpa->auxtrace.flush_events = powerpc_vpadtl_flush;
+ vpa->auxtrace.free_events = powerpc_vpadtl_free_events;
+ vpa->auxtrace.free = powerpc_vpadtl_free;
+ session->auxtrace = &vpa->auxtrace;
+
+ powerpc_vpadtl_print_info(&auxtrace_info->priv[0]);
+
+ return 0;
+
+err_free:
+ free(vpa);
+ return err;
+}
diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
index 50a7aa24acbe..aa76f5beac2c 100644
--- a/tools/perf/util/powerpc-vpadtl.h
+++ b/tools/perf/util/powerpc-vpadtl.h
@@ -15,4 +15,11 @@ enum {
#define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
+union perf_event;
+struct perf_session;
+struct perf_pmu;
+
+int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session);
+
#endif
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 3/6] tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to present DTL samples
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's Athira Rajeev
` (3 subsequent siblings)
6 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
Dispatch Trace Log details are captured as-is in PERF_RECORD_AUXTRACE
records. To present dtl entries as samples, create an event with name as
"vpa-dtl" and type PERF_TYPE_SYNTH. Add perf_synth_id,
"PERF_SYNTH_POWERPC_VPA_DTL" as config value for the event. Create a
sample id to be a fixed offset from evsel id.
To present the relevant fields from the "struct dtl_entry",
prepare the entries as events of type PERF_TYPE_SYNTH. By
defining as PERF_TYPE_SYNTH type, samples can be printed as part of
perf_sample__fprintf_synth in builtin-script.c
From powerpc_vpadtl_process_auxtrace_info(), invoke
auxtrace_queues__process_index() function which will queue the
auxtrace buffers by invoke auxtrace_queues__add_event().
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
tools/perf/util/event.h | 1 +
tools/perf/util/powerpc-vpadtl.c | 76 ++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 7ba208ae86fd..7e0e58979e9c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -117,6 +117,7 @@ enum perf_synth_id {
PERF_SYNTH_INTEL_PSB,
PERF_SYNTH_INTEL_EVT,
PERF_SYNTH_INTEL_IFLAG_CHG,
+ PERF_SYNTH_POWERPC_VPA_DTL,
};
/*
diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
index 2e8488a3dbd7..9098cbe00bfd 100644
--- a/tools/perf/util/powerpc-vpadtl.c
+++ b/tools/perf/util/powerpc-vpadtl.c
@@ -3,6 +3,7 @@
* VPA DTL PMU support
*/
+#include <linux/string.h>
#include <inttypes.h>
#include "color.h"
#include "evlist.h"
@@ -21,6 +22,7 @@ struct powerpc_vpadtl {
struct perf_session *session;
struct machine *machine;
u32 pmu_type;
+ u64 sample_id;
};
struct boottb_freq {
@@ -214,6 +216,65 @@ static void powerpc_vpadtl_print_info(__u64 *arr)
fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]);
}
+static void set_event_name(struct evlist *evlist, u64 id,
+ const char *name)
+{
+ struct evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel->core.id && evsel->core.id[0] == id) {
+ if (evsel->name)
+ zfree(&evsel->name);
+ evsel->name = strdup(name);
+ break;
+ }
+ }
+}
+
+static int
+powerpc_vpadtl_synth_events(struct powerpc_vpadtl *vpa, struct perf_session *session)
+{
+ struct evlist *evlist = session->evlist;
+ struct evsel *evsel;
+ struct perf_event_attr attr;
+ bool found = false;
+ u64 id;
+ int err;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (strstarts(evsel->name, "vpa_dtl")) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_debug("No selected events with VPA trace data\n");
+ return 0;
+ }
+
+ memset(&attr, 0, sizeof(struct perf_event_attr));
+ attr.size = sizeof(struct perf_event_attr);
+ attr.sample_type = evsel->core.attr.sample_type;
+ attr.sample_id_all = evsel->core.attr.sample_id_all;
+ attr.type = PERF_TYPE_SYNTH;
+ attr.config = PERF_SYNTH_POWERPC_VPA_DTL;
+
+ /* create new id val to be a fixed offset from evsel id */
+ id = evsel->core.id[0] + 1000000000;
+ if (!id)
+ id = 1;
+
+ err = perf_session__deliver_synth_attr_event(session, &attr, id);
+ if (err)
+ return err;
+
+ vpa->sample_id = id;
+ set_event_name(evlist, id, "vpa-dtl");
+
+ return 0;
+}
+
/*
* Process the PERF_RECORD_AUXTRACE_INFO records and setup
* the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO
@@ -255,8 +316,23 @@ int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
powerpc_vpadtl_print_info(&auxtrace_info->priv[0]);
+ if (dump_trace)
+ return 0;
+
+ err = powerpc_vpadtl_synth_events(vpa, session);
+ if (err)
+ goto err_free_queues;
+
+ err = auxtrace_queues__process_index(&vpa->queues, session);
+ if (err)
+ goto err_free_queues;
+
return 0;
+err_free_queues:
+ auxtrace_queues__free(&vpa->queues);
+ session->auxtrace = NULL;
+
err_free:
free(vpa);
return err;
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
` (2 preceding siblings ...)
2025-09-15 7:27 ` [PATCH V2 3/6] tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to present DTL samples Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-15 7:27 ` [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples Athira Rajeev
` (2 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
When the Dispatch Trace Log data is collected along with other events
like sched tracepoint events, it needs to be correlated and present
interleaved along with these events. Perf events can be collected
parallely across the CPUs. Hence it needs to be ensured events/dtl
entries are processed in timestamp order.
An auxtrace_queue is created for each CPU. Data within each queue is in
increasing order of timestamp. Each auxtrace queue has a array/list of
auxtrace buffers. When processing the auxtrace buffer, the data is
mmapp'ed. All auxtrace queues is maintained in auxtrace heap. Each queue
has a queue number and a timestamp. The queues are sorted/added to head
based on the time stamp. So always the lowest timestamp (entries to be
processed first) is on top of the heap.
The auxtrace queue needs to be allocated and heap needs to be populated
in the sorted order of timestamp. The queue needs to be filled with data
only once via powerpc_vpadtl__update_queues() function.
powerpc_vpadtl__setup_queues() iterates through all the entries to
allocate and setup the auxtrace queue. To add to auxtrace heap, it is
required to fetch the timebase of first entry for each of the queue.
The first entry in the queue for VPA DTL PMU has the boot timebase,
frequency details which are needed to get timestamp which is required to
correlate with other events. The very next entry is the actual trace data
that provides timestamp for occurrence of DTL event. Formula used to get
the timestamp from dtl entry is:
((timbase from DTL entry - boot time) / frequency) * 1000000000
powerpc_vpadtl_decode() adds the boot time and frequency as part of
powerpc_vpadtl_queue structure so that it can be reused. Each of the
dtl_entry is of 48 bytes size. Sometimes it could happen that one buffer
is only partially processed (if the timestamp of occurrence of another
event is more than currently processed element in queue, it will move on
to next event). In order to keep track of position of buffer, additional
fields is added to powerpc_vpadtl_queue structure.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changelog:
Addressed review comments from Adrian
- Moved time calculation to separate function
tools/perf/util/powerpc-vpadtl.c | 226 ++++++++++++++++++++++++++++++-
1 file changed, 223 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
index 9098cbe00bfd..637abde60f44 100644
--- a/tools/perf/util/powerpc-vpadtl.c
+++ b/tools/perf/util/powerpc-vpadtl.c
@@ -10,6 +10,8 @@
#include "session.h"
#include "debug.h"
#include "powerpc-vpadtl.h"
+#include "sample.h"
+#include "tool.h"
/*
* Structure to save the auxtrace queue
@@ -38,6 +40,14 @@ struct powerpc_vpadtl_queue {
struct auxtrace_buffer *buffer;
struct thread *thread;
bool on_heap;
+ struct powerpc_vpadtl_entry *dtl;
+ u64 timestamp;
+ unsigned long pkt_len;
+ unsigned long buf_len;
+ u64 boot_tb;
+ u64 tb_freq;
+ unsigned int tb_buffer;
+ unsigned int size;
bool done;
pid_t pid;
pid_t tid;
@@ -112,6 +122,33 @@ static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
}
}
+static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq)
+{
+ struct powerpc_vpadtl_entry *record = vpaq->dtl;
+ double result, div;
+ double boot_freq;
+ unsigned long long boot_tb;
+ unsigned long long diff;
+ unsigned long long timestamp = 0;
+
+ /*
+ * Formula used to get timestamp that can be co-related with
+ * other perf events:
+ * ((timbase from DTL entry - boot time) / frequency) * 1000000000
+ */
+ if (record->timebase) {
+ boot_tb = vpaq->boot_tb;
+ boot_freq = vpaq->tb_freq;
+ diff = be64_to_cpu(record->timebase) - boot_tb;
+ div = diff / boot_freq;
+ result = div;
+ result = result * 1000000000;
+ timestamp = result;
+ }
+
+ return timestamp;
+}
+
static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
{
return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
@@ -124,12 +161,195 @@ static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char
powerpc_vpadtl_dump(vpa, buf, len);
}
+static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
+{
+ struct auxtrace_buffer *buffer = vpaq->buffer;
+ struct auxtrace_queues *queues = &vpaq->vpa->queues;
+ struct auxtrace_queue *queue;
+
+ queue = &queues->queue_array[vpaq->queue_nr];
+ buffer = auxtrace_buffer__next(queue, buffer);
+
+ if (!buffer)
+ return 0;
+
+ vpaq->buffer = buffer;
+ vpaq->size = buffer->size;
+
+ /* If the aux_buffer doesn't have data associated, try to load it */
+ if (!buffer->data) {
+ /* get the file desc associated with the perf data file */
+ int fd = perf_data__fd(vpaq->vpa->session->data);
+
+ buffer->data = auxtrace_buffer__get_data(buffer, fd);
+ if (!buffer->data)
+ return -ENOMEM;
+ }
+
+ vpaq->buf_len = buffer->size;
+
+ if (buffer->size % dtl_entry_size)
+ vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size);
+
+ if (vpaq->tb_buffer != buffer->buffer_nr) {
+ vpaq->pkt_len = 0;
+ vpaq->tb_buffer = 0;
+ }
+
+ return 1;
+}
+
+/*
+ * The first entry in the queue for VPA DTL PMU has the boot timebase,
+ * frequency details which are needed to get timestamp which is required to
+ * correlate with other events. Save the boot_tb and tb_freq as part of
+ * powerpc_vpadtl_queue. The very next entry is the actual trace data to
+ * be returned.
+ */
+static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
+{
+ int ret;
+ char *buf;
+ struct boottb_freq *boottb;
+
+ ret = powerpc_vpadtl_get_buffer(vpaq);
+ if (ret <= 0)
+ return ret;
+
+ boottb = (struct boottb_freq *)vpaq->buffer->data;
+ if (boottb->timebase == 0) {
+ vpaq->boot_tb = boottb->boot_tb;
+ vpaq->tb_freq = boottb->tb_freq;
+ vpaq->pkt_len += dtl_entry_size;
+ }
+
+ buf = vpaq->buffer->data;
+ buf += vpaq->pkt_len;
+ vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
+
+ vpaq->tb_buffer = vpaq->buffer->buffer_nr;
+ vpaq->buffer = NULL;
+ vpaq->buf_len = 0;
+
+ return 1;
+}
+
+static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
+ unsigned int queue_nr)
+{
+ struct powerpc_vpadtl_queue *vpaq;
+
+ vpaq = zalloc(sizeof(*vpaq));
+ if (!vpaq)
+ return NULL;
+
+ vpaq->vpa = vpa;
+ vpaq->queue_nr = queue_nr;
+
+ return vpaq;
+}
+
+/*
+ * When the Dispatch Trace Log data is collected along with other events
+ * like sched tracepoint events, it needs to be correlated and present
+ * interleaved along with these events. Perf events can be collected
+ * parallely across the CPUs.
+ *
+ * An auxtrace_queue is created for each CPU. Data within each queue is in
+ * increasing order of timestamp. Allocate and setup auxtrace queues here.
+ * All auxtrace queues is maintained in auxtrace heap in the increasing order
+ * of timestamp. So always the lowest timestamp (entries to be processed first)
+ * is on top of the heap.
+ *
+ * To add to auxtrace heap, fetch the timestamp from first DTL entry
+ * for each of the queue.
+ */
+static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa,
+ struct auxtrace_queue *queue,
+ unsigned int queue_nr)
+{
+ struct powerpc_vpadtl_queue *vpaq = queue->priv;
+
+ if (list_empty(&queue->head) || vpaq)
+ return 0;
+
+ vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr);
+ if (!vpaq)
+ return -ENOMEM;
+
+ queue->priv = vpaq;
+
+ if (queue->cpu != -1)
+ vpaq->cpu = queue->cpu;
+
+ if (!vpaq->on_heap) {
+ int ret;
+retry:
+ ret = powerpc_vpadtl_decode(vpaq);
+ if (!ret)
+ return 0;
+
+ if (ret < 0)
+ goto retry;
+
+ vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq);
+
+ ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp);
+ if (ret)
+ return ret;
+ vpaq->on_heap = true;
+ }
+
+ return 0;
+}
+
+static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < vpa->queues.nr_queues; i++) {
+ ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa)
+{
+ if (vpa->queues.new_data) {
+ vpa->queues.new_data = false;
+ return powerpc_vpadtl__setup_queues(vpa);
+ }
+
+ return 0;
+}
+
static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
union perf_event *event __maybe_unused,
- struct perf_sample *sample __maybe_unused,
- const struct perf_tool *tool __maybe_unused)
+ struct perf_sample *sample,
+ const struct perf_tool *tool)
{
- return 0;
+ struct powerpc_vpadtl *vpa = session_to_vpa(session);
+ int err = 0;
+
+ if (dump_trace)
+ return 0;
+
+ if (!tool->ordered_events) {
+ pr_err("VPA requires ordered events\n");
+ return -EINVAL;
+ }
+
+ if (sample->time) {
+ err = powerpc_vpadtl__update_queues(vpa);
+ if (err)
+ return err;
+ }
+
+ return err;
}
/*
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
` (3 preceding siblings ...)
2025-09-15 7:27 ` [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-15 7:27 ` [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries Athira Rajeev
2025-09-15 16:07 ` [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Venkat
6 siblings, 1 reply; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
Create samples from DTL entries for displaying in perf report
and perf script. When the different PERF_RECORD_XX records are
processed from perf session, powerpc_vpadtl_process_event() will
be invoked. For each of the PERF_RECORD_XX record, compare the timestamp
of perf record with timestamp of top element in the auxtrace heap.
Process the auxtrace queue if the timestamp of element from heap is
lower than timestamp from entry in perf record.
Sometimes it could happen that one buffer is only partially
processed. if the timestamp of occurrence of another event is more
than currently processed element in the queue, it will move on
to next perf record. So keep track of position of buffer to
continue processing next time. Update the timestamp of the
auxtrace heap with the timestamp of last processed entry from
the auxtrace buffer.
Generate perf sample for each entry in the dispatch trace log.
Fill in the sample details:
- sample ip is picked from srr0 field of dtl_entry
- sample cpu is picked from processor_id of dtl_entry
- sample id is from sample_id of powerpc_vpadtl
- cpumode is set to PERF_RECORD_MISC_KERNEL
- Additionally save the details in raw_data of sample. This
is to print the relevant fields in perf_sample__fprintf_synth()
when called from builtin-script
The sample is processed by calling perf_session__deliver_synth_event()
so that it gets included in perf report.
Sample Output:
./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.300 MB perf.data ]
./perf report
# Samples: 321 of event 'vpa-dtl'
# Event count (approx.): 321
#
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ..............................
#
100.00% 100.00% swapper [kernel.kallsyms] [k] plpar_hcall_norets_notrace
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changelog:
Addressed review comments from Adrian:
- Moved time calculation to different function
- Alignment and wording changes
tools/perf/util/powerpc-vpadtl.c | 173 +++++++++++++++++++++++++++++++
1 file changed, 173 insertions(+)
diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
index 637abde60f44..dc437dae16b8 100644
--- a/tools/perf/util/powerpc-vpadtl.c
+++ b/tools/perf/util/powerpc-vpadtl.c
@@ -161,6 +161,43 @@ static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char
powerpc_vpadtl_dump(vpa, buf, len);
}
+/*
+ * Generate perf sample for each entry in the dispatch trace log.
+ * - sample ip is picked from srr0 field of powerpc_vpadtl_entry
+ * - sample cpu is logical cpu.
+ * - cpumode is set to PERF_RECORD_MISC_KERNEL
+ * - Additionally save the details in raw_data of sample. This
+ * is to print the relevant fields in perf_sample__fprintf_synth()
+ * when called from builtin-script
+ */
+static int powerpc_vpadtl_sample(struct powerpc_vpadtl_entry *record, struct powerpc_vpadtl *vpa, u64 save, int cpu)
+{
+ struct perf_sample sample;
+ union perf_event event;
+
+ sample.ip = be64_to_cpu(record->srr0);
+ sample.period = 1;
+ sample.cpu = cpu;
+ sample.id = vpa->sample_id;
+ sample.callchain = NULL;
+ sample.branch_stack = NULL;
+ memset(&event, 0, sizeof(event));
+ sample.cpumode = PERF_RECORD_MISC_KERNEL;
+ sample.time = save;
+ sample.raw_data = record;
+ sample.raw_size = sizeof(record);
+ event.sample.header.type = PERF_RECORD_SAMPLE;
+ event.sample.header.misc = sample.cpumode;
+ event.sample.header.size = sizeof(struct perf_event_header);
+
+ if (perf_session__deliver_synth_event(vpa->session, &event, &sample)) {
+ pr_debug("Failed to create sample for dtl entry\n");
+ return -1;
+ }
+
+ return 0;
+}
+
static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
{
struct auxtrace_buffer *buffer = vpaq->buffer;
@@ -234,6 +271,140 @@ static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
return 1;
}
+static int powerpc_vpadtl_decode_all(struct powerpc_vpadtl_queue *vpaq)
+{
+ int ret;
+ unsigned char *buf;
+
+ if (!vpaq->buf_len || vpaq->pkt_len == vpaq->size) {
+ ret = powerpc_vpadtl_get_buffer(vpaq);
+ if (ret <= 0)
+ return ret;
+ }
+
+ if (vpaq->buffer) {
+ buf = vpaq->buffer->data;
+ buf += vpaq->pkt_len;
+ vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
+ if ((long long)be64_to_cpu(vpaq->dtl->timebase) <= 0) {
+ if (vpaq->pkt_len != dtl_entry_size && vpaq->buf_len) {
+ vpaq->pkt_len += dtl_entry_size;
+ vpaq->buf_len -= dtl_entry_size;
+ }
+ return -1;
+ }
+ vpaq->pkt_len += dtl_entry_size;
+ vpaq->buf_len -= dtl_entry_size;
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int powerpc_vpadtl_run_decoder(struct powerpc_vpadtl_queue *vpaq, u64 *timestamp)
+{
+ struct powerpc_vpadtl *vpa = vpaq->vpa;
+ struct powerpc_vpadtl_entry *record;
+ int ret;
+ unsigned long long vpaq_timestamp;
+
+ while (1) {
+ ret = powerpc_vpadtl_decode_all(vpaq);
+ if (!ret) {
+ pr_debug("All data in the queue has been processed.\n");
+ return 1;
+ }
+
+ /*
+ * Error is detected when decoding VPA PMU trace. Continue to
+ * the next trace data and find out more dtl entries.
+ */
+ if (ret < 0)
+ continue;
+
+ record = vpaq->dtl;
+
+ vpaq_timestamp = powerpc_vpadtl_timestamp(vpaq);
+
+ /* Update timestamp for the last record */
+ if (vpaq_timestamp > vpaq->timestamp)
+ vpaq->timestamp = vpaq_timestamp;
+
+ /*
+ * If the timestamp of the queue is later than timestamp of the
+ * coming perf event, bail out so can allow the perf event to
+ * be processed ahead.
+ */
+ if (vpaq->timestamp >= *timestamp) {
+ *timestamp = vpaq->timestamp;
+ vpaq->pkt_len -= dtl_entry_size;
+ vpaq->buf_len += dtl_entry_size;
+ return 0;
+ }
+
+ ret = powerpc_vpadtl_sample(record, vpa, vpaq_timestamp, vpaq->cpu);
+ if (ret)
+ continue;
+ }
+ return 0;
+}
+
+/*
+ * For each of the PERF_RECORD_XX record, compare the timestamp
+ * of perf record with timestamp of top element in the auxtrace heap.
+ * Process the auxtrace queue if the timestamp of element from heap is
+ * lower than timestamp from entry in perf record.
+ *
+ * Update the timestamp of the auxtrace heap with the timestamp
+ * of last processed entry from the auxtrace buffer.
+ */
+static int powerpc_vpadtl_process_queues(struct powerpc_vpadtl *vpa, u64 timestamp)
+{
+ unsigned int queue_nr;
+ u64 ts;
+ int ret;
+
+ while (1) {
+ struct auxtrace_queue *queue;
+ struct powerpc_vpadtl_queue *vpaq;
+
+ if (!vpa->heap.heap_cnt)
+ return 0;
+
+ if (vpa->heap.heap_array[0].ordinal >= timestamp)
+ return 0;
+
+ queue_nr = vpa->heap.heap_array[0].queue_nr;
+ queue = &vpa->queues.queue_array[queue_nr];
+ vpaq = queue->priv;
+
+ auxtrace_heap__pop(&vpa->heap);
+
+ if (vpa->heap.heap_cnt) {
+ ts = vpa->heap.heap_array[0].ordinal + 1;
+ if (ts > timestamp)
+ ts = timestamp;
+ } else
+ ts = timestamp;
+
+ ret = powerpc_vpadtl_run_decoder(vpaq, &ts);
+ if (ret < 0) {
+ auxtrace_heap__add(&vpa->heap, queue_nr, ts);
+ return ret;
+ }
+
+ if (!ret) {
+ ret = auxtrace_heap__add(&vpa->heap, queue_nr, ts);
+ if (ret < 0)
+ return ret;
+ } else {
+ vpaq->on_heap = false;
+ }
+ }
+ return 0;
+}
+
static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
unsigned int queue_nr)
{
@@ -347,6 +518,8 @@ static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unu
err = powerpc_vpadtl__update_queues(vpa);
if (err)
return err;
+
+ err = powerpc_vpadtl_process_queues(vpa, sample->time);
}
return err;
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
` (4 preceding siblings ...)
2025-09-15 7:27 ` [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples Athira Rajeev
@ 2025-09-15 7:27 ` Athira Rajeev
2025-09-15 15:09 ` Adrian Hunter
2025-09-15 16:07 ` [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Venkat
6 siblings, 1 reply; 18+ messages in thread
From: Athira Rajeev @ 2025-09-15 7:27 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, atrajeev, hbathini,
Aditya.Bodkhe1, venkat88
The process_event() function in "builtin-script.c" invokes
perf_sample__fprintf_synth() for displaying PERF_TYPE_SYNTH
type events.
if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
perf_sample__fprintf_synth(sample, evsel, fp);
perf_sample__fprintf_synth() process the sample depending on the value
in evsel->core.attr.config. Introduce perf_sample__fprintf_synth_vpadtl()
and invoke this for PERF_SYNTH_POWERPC_VPA_DTL
Sample output:
./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.300 MB perf.data ]
./perf script
perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changelog:
Addressed review comments from Adrian
- Removed default callback and used perf_sample__fprintf_synth_vpadtl
- fix build failure when using NO_AUXTRACE=1 by
adding code around HAVE_AUXTRACE_SUPPORT
tools/perf/builtin-script.c | 27 +++++++++++++++++++++++++++
tools/perf/util/event.h | 3 +++
2 files changed, 30 insertions(+)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d9fbdcf72f25..8a03fdbfce5e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -43,6 +43,7 @@
#include <linux/stringify.h>
#include <linux/time64.h>
#include <linux/zalloc.h>
+#include <linux/unaligned.h>
#include <sys/utsname.h>
#include "asm/bug.h"
#include "util/mem-events.h"
@@ -2003,6 +2004,30 @@ static int perf_sample__fprintf_synth_iflag_chg(struct perf_sample *sample, FILE
return len + perf_sample__fprintf_pt_spacing(len, fp);
}
+#ifdef HAVE_AUXTRACE_SUPPORT
+static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data, FILE *fp)
+{
+ struct powerpc_vpadtl_entry *dtl = (struct powerpc_vpadtl_entry *)data->raw_data;
+
+ fprintf(fp, "timebase: %" PRIu64 " dispatch_reason:%s, preempt_reason:%s,\n"
+ "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, waiting_to_ready_time:%d, processor_id: %d",\
+ get_unaligned_be64(&dtl->timebase),
+ dispatch_reasons[dtl->dispatch_reason],
+ preempt_reasons[dtl->preempt_reason],
+ be32_to_cpu(dtl->enqueue_to_dispatch_time),
+ be32_to_cpu(dtl->ready_to_enqueue_time),
+ be32_to_cpu(dtl->waiting_to_ready_time),
+ be16_to_cpu(dtl->processor_id));
+
+ return 1;
+}
+#else
+static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data __maybe_unused, FILE *fp __maybe_unused)
+{
+ return 0;
+}
+#endif
+
static int perf_sample__fprintf_synth(struct perf_sample *sample,
struct evsel *evsel, FILE *fp)
{
@@ -2025,6 +2050,8 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,
return perf_sample__fprintf_synth_evt(sample, fp);
case PERF_SYNTH_INTEL_IFLAG_CHG:
return perf_sample__fprintf_synth_iflag_chg(sample, fp);
+ case PERF_SYNTH_POWERPC_VPA_DTL:
+ return perf_sample__fprintf_synth_vpadtl(sample, fp);
default:
break;
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 7e0e58979e9c..64c63b59d617 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -271,6 +271,9 @@ struct powerpc_vpadtl_entry {
u64 srr1;
};
+extern const char *dispatch_reasons[11];
+extern const char *preempt_reasons[10];
+
static inline void *perf_synth__raw_data(void *p)
{
return p + 4;
--
2.47.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
2025-09-15 7:27 ` [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc Athira Rajeev
@ 2025-09-15 15:07 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
0 siblings, 1 reply; 18+ messages in thread
From: Adrian Hunter @ 2025-09-15 15:07 UTC (permalink / raw)
To: Athira Rajeev, acme, jolsa, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1,
venkat88
On 15/09/2025 10:27, Athira Rajeev wrote:
> The powerpc PMU collecting Dispatch Trace Log (DTL) entries makes use of
> AUX support in perf infrastructure. The PMU driver has the functionality
> to collect trace entries in the aux buffer. On the tools side, this data
> is made available as PERF_RECORD_AUXTRACE records. This record is
> generated by "perf record" command. To enable the creation of
> PERF_RECORD_AUXTRACE, add functions to initialize auxtrace records ie
> "auxtrace_record__init()". Fill in fields for other callbacks like
> info_priv_size, info_fill, free, recording options etc. Define
> auxtrace_type as PERF_AUXTRACE_VPA_DTL. Add header file to define vpa
> dtl pmu specific details.
>
> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
> ---
> Changelog:
> Addressed review comments from Adrian:
> - Return VPADTL_AUXTRACE_PRIV_SIZE in powerpc_vpadtl_info_priv_size
> - Remove unused powerpc_vpadtl_parse_snapshot_options
> - Some of the function parameters had "__maybe_unused", corrected it.
> - Used PERF_AUXTRACE_VPA_DTL instead of PERF_AUXTRACE_VPA_PMU
> - Moved powerpc_vpadtl_process_auxtrace_info to next patch
>
> tools/perf/arch/powerpc/util/Build | 1 +
> tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++++++++++++++++++++++
> tools/perf/util/auxtrace.c | 1 +
> tools/perf/util/auxtrace.h | 1 +
> tools/perf/util/powerpc-vpadtl.h | 18 ++++
> 5 files changed, 135 insertions(+)
> create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
> create mode 100644 tools/perf/util/powerpc-vpadtl.h
>
> diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
> index fdd6a77a3432..a5b0babd307e 100644
> --- a/tools/perf/arch/powerpc/util/Build
> +++ b/tools/perf/arch/powerpc/util/Build
> @@ -10,3 +10,4 @@ perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
>
> perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
> perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> +perf-util-$(CONFIG_AUXTRACE) += auxtrace.o
> diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
> new file mode 100644
> index 000000000000..803c582c0c6f
> --- /dev/null
> +++ b/tools/perf/arch/powerpc/util/auxtrace.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * VPA support
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
> +#include <linux/log2.h>
Are bitops.h and log2.h needed?
> +#include <linux/string.h>
> +#include <time.h>
> +
> +#include "../../util/cpumap.h"
Is cpumap.h needed?
> +#include "../../util/evsel.h"
> +#include "../../util/evlist.h"
> +#include "../../util/session.h"
> +#include "../../util/util.h"
> +#include "../../util/pmu.h"
Is pmu.h needed?
> +#include "../../util/debug.h"
> +#include "../../util/auxtrace.h"
> +#include "../../util/powerpc-vpadtl.h"
> +#include "../../util/record.h"
> +#include <internal/lib.h> // page_size
> +
> +#define KiB(x) ((x) * 1024)
> +
> +static int
> +powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
> + struct evlist *evlist __maybe_unused,
> + struct record_opts *opts)
> +{
> + opts->full_auxtrace = true;
> +
> + /*
> + * Set auxtrace_mmap_pages to minimum
> + * two pages
> + */
> + if (!opts->auxtrace_mmap_pages) {
> + opts->auxtrace_mmap_pages = KiB(128) / page_size;
> + if (opts->mmap_pages == UINT_MAX)
> + opts->mmap_pages = KiB(256) / page_size;
> + }
> +
> + return 0;
> +}
> +
> +static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
> + struct evlist *evlist __maybe_unused)
> +{
> + return VPADTL_AUXTRACE_PRIV_SIZE;
> +}
> +
> +static int
> +powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
> + struct perf_session *session __maybe_unused,
> + struct perf_record_auxtrace_info *auxtrace_info,
> + size_t priv_size __maybe_unused)
> +{
> + auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
> +
> + return 0;
> +}
> +
> +static void powerpc_vpadtl_free(struct auxtrace_record *itr)
> +{
> + free(itr);
> +}
> +
> +static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
> +{
> + return 0;
> +}
> +
> +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
> + int *err)
> +{
> + struct auxtrace_record *aux;
> + struct evsel *pos;
> + char *pmu_name;
> + int found = 0;
> +
> + evlist__for_each_entry(evlist, pos) {
> + pmu_name = strdup(pos->name);
> + pmu_name = strtok(pmu_name, "/");
> + if (strstarts(pmu_name, "vpa_dtl")) {
pmu_name is leaked, but maybe it is not needed at all e.g.
if (strstarts(pos->name, "vpa_dtl")) {
> + found = 1;
> + pos->needs_auxtrace_mmap = true;
> + break;
> + }
> + }
> +
> + if (!found)
> + return NULL;
> +
> + /*
> + * To obtain the auxtrace buffer file descriptor, the auxtrace event
> + * must come first.
> + */
> + evlist__to_front(pos->evlist, pos);
> +
> + aux = zalloc(sizeof(*aux));
> + if (aux == NULL) {
> + pr_debug("aux record is NULL\n");
> + *err = -ENOMEM;
> + return NULL;
> + }
> +
> + aux->recording_options = powerpc_vpadtl_recording_options;
> + aux->info_priv_size = powerpc_vpadtl_info_priv_size;
> + aux->info_fill = powerpc_vpadtl_info_fill;
> + aux->free = powerpc_vpadtl_free;
> + aux->reference = powerpc_vpadtl_reference;
> + return aux;
> +}
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index ebd32f1b8f12..f294658bb948 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -1393,6 +1393,7 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
> case PERF_AUXTRACE_HISI_PTT:
> err = hisi_ptt_process_auxtrace_info(event, session);
> break;
> + case PERF_AUXTRACE_VPA_DTL:
> case PERF_AUXTRACE_UNKNOWN:
> default:
> return -EINVAL;
> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> index f001cbb68f8e..e0a5b39fed12 100644
> --- a/tools/perf/util/auxtrace.h
> +++ b/tools/perf/util/auxtrace.h
> @@ -50,6 +50,7 @@ enum auxtrace_type {
> PERF_AUXTRACE_ARM_SPE,
> PERF_AUXTRACE_S390_CPUMSF,
> PERF_AUXTRACE_HISI_PTT,
> + PERF_AUXTRACE_VPA_DTL,
> };
>
> enum itrace_period_type {
> diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
> new file mode 100644
> index 000000000000..50a7aa24acbe
> --- /dev/null
> +++ b/tools/perf/util/powerpc-vpadtl.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * VPA DTL PMU Support
> + */
> +
> +#ifndef INCLUDE__PERF_POWERPC_VPADTL_H__
> +#define INCLUDE__PERF_POWERPC_VPADTL_H__
> +
> +#define POWERPC_VPADTL_NAME "powerpc_vpadtl_"
Never used
> +
> +enum {
> + POWERPC_VPADTL_TYPE,
> + VPADTL_AUXTRACE_PRIV_MAX,
> +};
> +
> +#define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
> +
> +#endif
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D
2025-09-15 7:27 ` [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D Athira Rajeev
@ 2025-09-15 15:08 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
0 siblings, 1 reply; 18+ messages in thread
From: Adrian Hunter @ 2025-09-15 15:08 UTC (permalink / raw)
To: Athira Rajeev, acme, jolsa, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1,
venkat88
On 15/09/2025 10:27, Athira Rajeev wrote:
> Add vpa dtl pmu auxtrace process function for "perf report -D".
> The auxtrace event processing functions are defined in file
> "util/powerpc-vpadtl.c". Data structures used includes "struct
> powerpc_vpadtl_queue", "struct powerpc_vpadtl" to store the auxtrace
> buffers in queue. Different PERF_RECORD_XXX are generated
> during recording. PERF_RECORD_AUXTRACE_INFO is processed first
> since it is of type perf_user_event_type and perf session event
> delivers perf_session__process_user_event() first. Define function
> powerpc_vpadtl_process_auxtrace_info() to handle the processing of
> PERF_RECORD_AUXTRACE_INFO records. In this function, initialize
> the aux buffer queues using auxtrace_queues__init(). Setup the
> required infrastructure for aux data processing. The data is collected
> per CPU and auxtrace_queue is created for each CPU.
>
> Define powerpc_vpadtl_process_event() function to process
> PERF_RECORD_AUXTRACE records. In this, add the event to queue using
> auxtrace_queues__add_event() and process the buffer in
> powerpc_vpadtl_dump_event(). The first entry in the buffer with
> timebase as zero has boot timebase and frequency. Remaining data is of
> format for "struct powerpc_vpadtl_entry". Define the translation for
> dispatch_reasons and preempt_reasons, report this when dump trace is
> invoked via powerpc_vpadtl_dump()
>
> Sample output:
>
> ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.300 MB perf.data ]
>
> ./perf report -D
>
> 0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
> .
> . ... VPA DTL PMU data: size 1680 bytes, entries is 35
> . 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
> . 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
> . 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
> . 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
> . 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
> . 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
> . 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
> . 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
> . 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
>
> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
> ---
> Changelog:
> Addressed review comments from Adrian
> - Renamed dtl_entry to powerpc_vpadtl_entry in util/event.h
> - Removed unused #includes in powerpc-vpadtl.c
> - Added helper session_to_vpa to get "struct powerpc_vpadtl"
> - Updated auxtrace_queues__add_event only for piped data
> - Used zfree to free "struct powerpc_vpadtl_queue"
>
> tools/perf/util/Build | 1 +
> tools/perf/util/auxtrace.c | 3 +
> tools/perf/util/event.h | 16 ++
> tools/perf/util/powerpc-vpadtl.c | 263 +++++++++++++++++++++++++++++++
> tools/perf/util/powerpc-vpadtl.h | 7 +
> 5 files changed, 290 insertions(+)
> create mode 100644 tools/perf/util/powerpc-vpadtl.c
>
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 4959e7a990e4..5ead46dc98e7 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -136,6 +136,7 @@ perf-util-$(CONFIG_AUXTRACE) += arm-spe-decoder/
> perf-util-$(CONFIG_AUXTRACE) += hisi-ptt.o
> perf-util-$(CONFIG_AUXTRACE) += hisi-ptt-decoder/
> perf-util-$(CONFIG_AUXTRACE) += s390-cpumsf.o
> +perf-util-$(CONFIG_AUXTRACE) += powerpc-vpadtl.o
>
> ifdef CONFIG_LIBOPENCSD
> perf-util-$(CONFIG_AUXTRACE) += cs-etm.o
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index f294658bb948..6d10f3d61ff8 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -55,6 +55,7 @@
> #include "hisi-ptt.h"
> #include "s390-cpumsf.h"
> #include "util/mmap.h"
> +#include "powerpc-vpadtl.h"
>
> #include <linux/ctype.h>
> #include "symbol/kallsyms.h"
> @@ -1394,6 +1395,8 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
> err = hisi_ptt_process_auxtrace_info(event, session);
> break;
> case PERF_AUXTRACE_VPA_DTL:
> + err = powerpc_vpadtl_process_auxtrace_info(event, session);
> + break;
> case PERF_AUXTRACE_UNKNOWN:
> default:
> return -EINVAL;
> diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
> index e40d16d3246c..7ba208ae86fd 100644
> --- a/tools/perf/util/event.h
> +++ b/tools/perf/util/event.h
> @@ -254,6 +254,22 @@ struct perf_synth_intel_iflag_chg {
> u64 branch_ip; /* If via_branch */
> };
>
> +/*
> + * The powerpc VPA DTL entries are of below format
> + */
> +struct powerpc_vpadtl_entry {
> + u8 dispatch_reason;
> + u8 preempt_reason;
> + u16 processor_id;
> + u32 enqueue_to_dispatch_time;
> + u32 ready_to_enqueue_time;
> + u32 waiting_to_ready_time;
> + u64 timebase;
> + u64 fault_addr;
> + u64 srr0;
> + u64 srr1;
> +};
> +
> static inline void *perf_synth__raw_data(void *p)
> {
> return p + 4;
> diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
> new file mode 100644
> index 000000000000..2e8488a3dbd7
> --- /dev/null
> +++ b/tools/perf/util/powerpc-vpadtl.c
> @@ -0,0 +1,263 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * VPA DTL PMU support
> + */
> +
> +#include <inttypes.h>
> +#include "color.h"
> +#include "evlist.h"
> +#include "session.h"
Should really also:
#include "auxtrace.h"
#include "data.h"
#include "machine.h"
> +#include "debug.h"
> +#include "powerpc-vpadtl.h"
> +
> +/*
> + * Structure to save the auxtrace queue
> + */
> +struct powerpc_vpadtl {
> + struct auxtrace auxtrace;
> + struct auxtrace_queues queues;
> + struct auxtrace_heap heap;
> + u32 auxtrace_type;
> + struct perf_session *session;
> + struct machine *machine;
> + u32 pmu_type;
> +};
> +
> +struct boottb_freq {
> + u64 boot_tb;
> + u64 tb_freq;
> + u64 timebase;
> + u64 padded[3];
> +};
> +
> +struct powerpc_vpadtl_queue {
> + struct powerpc_vpadtl *vpa;
> + unsigned int queue_nr;
> + struct auxtrace_buffer *buffer;
> + struct thread *thread;
> + bool on_heap;
> + bool done;
> + pid_t pid;
> + pid_t tid;
> + int cpu;
> +};
> +
> +const char *dispatch_reasons[11] = {
> + "external_interrupt",
> + "firmware_internal_event",
> + "H_PROD",
> + "decrementer_interrupt",
> + "system_reset",
> + "firmware_internal_event",
> + "conferred_cycles",
> + "time_slice",
> + "virtual_memory_page_fault",
> + "expropriated_adjunct",
> + "priv_doorbell"};
> +
> +const char *preempt_reasons[10] = {
> + "unused",
> + "firmware_internal_event",
> + "H_CEDE",
> + "H_CONFER",
> + "time_slice",
> + "migration_hibernation_page_fault",
> + "virtual_memory_page_fault",
> + "H_CONFER_ADJUNCT",
> + "hcall_adjunct",
> + "HDEC_adjunct"};
> +
> +#define dtl_entry_size sizeof(struct powerpc_vpadtl_entry)
> +
> +/*
> + * Function to dump the dispatch trace data when perf report
> + * is invoked with -D
> + */
> +static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
> + unsigned char *buf, size_t len)
> +{
> + struct powerpc_vpadtl_entry *dtl;
> + int pkt_len, pos = 0;
> + const char *color = PERF_COLOR_BLUE;
> +
> + color_fprintf(stdout, color,
> + ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n",
> + len, len/dtl_entry_size);
> +
> + if (len % dtl_entry_size)
> + len = len - (len % dtl_entry_size);
> +
> + while (len) {
> + pkt_len = dtl_entry_size;
> + printf(".");
> + color_fprintf(stdout, color, " %08x: ", pos);
> + dtl = (struct powerpc_vpadtl_entry *)buf;
> + if (dtl->timebase != 0) {
> + printf("dispatch_reason:%s, preempt_reason:%s, enqueue_to_dispatch_time:%d,"
> + "ready_to_enqueue_time:%d, waiting_to_ready_time:%d\n",
> + dispatch_reasons[dtl->dispatch_reason], preempt_reasons[dtl->preempt_reason],\
> + be32_to_cpu(dtl->enqueue_to_dispatch_time),\
> + be32_to_cpu(dtl->ready_to_enqueue_time), be32_to_cpu(dtl->waiting_to_ready_time));
Better if these lines were 100 columns or less
> + } else {
> + struct boottb_freq *boot_tb = (struct boottb_freq *)buf;
> +
> + printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n", boot_tb->boot_tb, boot_tb->tb_freq);
Better if this lines was 100 columns or less
> + }
> +
> + pos += pkt_len;
> + buf += pkt_len;
> + len -= pkt_len;
> + }
> +}
> +
> +static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
> +{
> + return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
> +}
> +
> +static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf,
> + size_t len)
> +{
> + printf(".\n");
> + powerpc_vpadtl_dump(vpa, buf, len);
> +}
> +
> +static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
> + union perf_event *event __maybe_unused,
> + struct perf_sample *sample __maybe_unused,
> + const struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +/*
> + * Process PERF_RECORD_AUXTRACE records
> + */
> +static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session,
> + union perf_event *event,
> + const struct perf_tool *tool __maybe_unused)
> +{
> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
> + struct auxtrace_buffer *buffer;
> + int fd = perf_data__fd(session->data);
> + off_t data_offset;
> + int err;
> +
> + if (!dump_trace)
> + return 0;
> +
> + if (perf_data__is_pipe(session->data)) {
> + data_offset = 0;
> + } else {
> + data_offset = lseek(fd, 0, SEEK_CUR);
> + if (data_offset == -1)
> + return -errno;
> + }
> +
> + err = auxtrace_queues__add_event(&vpa->queues, session, event,
> + data_offset, &buffer);
> +
> + if (err)
> + return err;
> +
> + /* Dump here now we have copied a piped trace out of the pipe */
> + if (auxtrace_buffer__get_data(buffer, fd)) {
> + powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size);
> + auxtrace_buffer__put_data(buffer);
> + }
> +
> + return 0;
> +}
> +
> +static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused,
> + const struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static void powerpc_vpadtl_free_events(struct perf_session *session)
> +{
> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
> + struct auxtrace_queues *queues = &vpa->queues;
> + struct powerpc_vpadtl_queue *vpaq;
> +
> + unsigned int i;
> +
> + for (i = 0; i < queues->nr_queues; i++) {
Modern style allows int decl. inside for() e.g.
for (int i = 0; i < queues->nr_queues; i++) {
> + vpaq = queues->queue_array[i].priv;
> + if (vpaq)
> + zfree(&vpaq);
free() can handle NULL, so vpaq not needed, just
zfree(&queues->queue_array[i].priv);
> + }
> +
> + auxtrace_queues__free(queues);
> +}
> +
> +static void powerpc_vpadtl_free(struct perf_session *session)
> +{
> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
> +
> + auxtrace_heap__free(&vpa->heap);
> + powerpc_vpadtl_free_events(session);
> + session->auxtrace = NULL;
> + free(vpa);
> +}
> +
> +static const char * const powerpc_vpadtl_info_fmts[] = {
> + [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n",
> +};
> +
> +static void powerpc_vpadtl_print_info(__u64 *arr)
> +{
> + if (!dump_trace)
> + return;
> +
> + fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]);
> +}
> +
> +/*
> + * Process the PERF_RECORD_AUXTRACE_INFO records and setup
> + * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO
> + * is processed first since it is of type perf_user_event_type.
> + * Initialise the aux buffer queues using auxtrace_queues__init().
> + * auxtrace_queue is created for each CPU.
> + */
> +int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session)
> +{
> + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
> + size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE;
> + struct powerpc_vpadtl *vpa;
> + int err;
> +
> + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
> + min_sz)
> + return -EINVAL;
> +
> + vpa = zalloc(sizeof(struct powerpc_vpadtl));
> + if (!vpa)
> + return -ENOMEM;
> +
> + err = auxtrace_queues__init(&vpa->queues);
> + if (err)
> + goto err_free;
> +
> + vpa->session = session;
> + vpa->machine = &session->machines.host; /* No kvm support */
> + vpa->auxtrace_type = auxtrace_info->type;
> + vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE];
> +
> + vpa->auxtrace.process_event = powerpc_vpadtl_process_event;
> + vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event;
> + vpa->auxtrace.flush_events = powerpc_vpadtl_flush;
> + vpa->auxtrace.free_events = powerpc_vpadtl_free_events;
> + vpa->auxtrace.free = powerpc_vpadtl_free;
> + session->auxtrace = &vpa->auxtrace;
> +
> + powerpc_vpadtl_print_info(&auxtrace_info->priv[0]);
> +
> + return 0;
> +
> +err_free:
> + free(vpa);
> + return err;
> +}
> diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
> index 50a7aa24acbe..aa76f5beac2c 100644
> --- a/tools/perf/util/powerpc-vpadtl.h
> +++ b/tools/perf/util/powerpc-vpadtl.h
> @@ -15,4 +15,11 @@ enum {
>
> #define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
>
> +union perf_event;
> +struct perf_session;
> +struct perf_pmu;
> +
> +int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session);
> +
> #endif
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's
2025-09-15 7:27 ` [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's Athira Rajeev
@ 2025-09-15 15:08 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
0 siblings, 1 reply; 18+ messages in thread
From: Adrian Hunter @ 2025-09-15 15:08 UTC (permalink / raw)
To: Athira Rajeev, acme, jolsa, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1,
venkat88
On 15/09/2025 10:27, Athira Rajeev wrote:
> When the Dispatch Trace Log data is collected along with other events
> like sched tracepoint events, it needs to be correlated and present
> interleaved along with these events. Perf events can be collected
> parallely across the CPUs. Hence it needs to be ensured events/dtl
> entries are processed in timestamp order.
>
> An auxtrace_queue is created for each CPU. Data within each queue is in
> increasing order of timestamp. Each auxtrace queue has a array/list of
> auxtrace buffers. When processing the auxtrace buffer, the data is
> mmapp'ed. All auxtrace queues is maintained in auxtrace heap. Each queue
> has a queue number and a timestamp. The queues are sorted/added to head
> based on the time stamp. So always the lowest timestamp (entries to be
> processed first) is on top of the heap.
>
> The auxtrace queue needs to be allocated and heap needs to be populated
> in the sorted order of timestamp. The queue needs to be filled with data
> only once via powerpc_vpadtl__update_queues() function.
> powerpc_vpadtl__setup_queues() iterates through all the entries to
> allocate and setup the auxtrace queue. To add to auxtrace heap, it is
> required to fetch the timebase of first entry for each of the queue.
>
> The first entry in the queue for VPA DTL PMU has the boot timebase,
> frequency details which are needed to get timestamp which is required to
> correlate with other events. The very next entry is the actual trace data
> that provides timestamp for occurrence of DTL event. Formula used to get
> the timestamp from dtl entry is:
>
> ((timbase from DTL entry - boot time) / frequency) * 1000000000
>
> powerpc_vpadtl_decode() adds the boot time and frequency as part of
> powerpc_vpadtl_queue structure so that it can be reused. Each of the
> dtl_entry is of 48 bytes size. Sometimes it could happen that one buffer
> is only partially processed (if the timestamp of occurrence of another
> event is more than currently processed element in queue, it will move on
> to next event). In order to keep track of position of buffer, additional
> fields is added to powerpc_vpadtl_queue structure.
>
> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
> ---
> Changelog:
> Addressed review comments from Adrian
> - Moved time calculation to separate function
>
> tools/perf/util/powerpc-vpadtl.c | 226 ++++++++++++++++++++++++++++++-
> 1 file changed, 223 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
> index 9098cbe00bfd..637abde60f44 100644
> --- a/tools/perf/util/powerpc-vpadtl.c
> +++ b/tools/perf/util/powerpc-vpadtl.c
> @@ -10,6 +10,8 @@
> #include "session.h"
> #include "debug.h"
> #include "powerpc-vpadtl.h"
> +#include "sample.h"
> +#include "tool.h"
>
> /*
> * Structure to save the auxtrace queue
> @@ -38,6 +40,14 @@ struct powerpc_vpadtl_queue {
> struct auxtrace_buffer *buffer;
> struct thread *thread;
> bool on_heap;
> + struct powerpc_vpadtl_entry *dtl;
> + u64 timestamp;
> + unsigned long pkt_len;
> + unsigned long buf_len;
> + u64 boot_tb;
> + u64 tb_freq;
> + unsigned int tb_buffer;
> + unsigned int size;
> bool done;
> pid_t pid;
> pid_t tid;
> @@ -112,6 +122,33 @@ static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
> }
> }
>
> +static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq)
> +{
> + struct powerpc_vpadtl_entry *record = vpaq->dtl;
> + double result, div;
> + double boot_freq;
> + unsigned long long boot_tb;
> + unsigned long long diff;
> + unsigned long long timestamp = 0;
Prettier in descending line length e.g.
struct powerpc_vpadtl_entry *record = vpaq->dtl;
unsigned long long timestamp = 0;
unsigned long long boot_tb;
unsigned long long diff;
double result, div;
double boot_freq;
> +
> + /*
> + * Formula used to get timestamp that can be co-related with
> + * other perf events:
> + * ((timbase from DTL entry - boot time) / frequency) * 1000000000
> + */
> + if (record->timebase) {
> + boot_tb = vpaq->boot_tb;
> + boot_freq = vpaq->tb_freq;
> + diff = be64_to_cpu(record->timebase) - boot_tb;
> + div = diff / boot_freq;
> + result = div;
> + result = result * 1000000000;
> + timestamp = result;
> + }
> +
> + return timestamp;
> +}
> +
> static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
> {
> return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
> @@ -124,12 +161,195 @@ static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char
> powerpc_vpadtl_dump(vpa, buf, len);
> }
>
> +static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
> +{
> + struct auxtrace_buffer *buffer = vpaq->buffer;
> + struct auxtrace_queues *queues = &vpaq->vpa->queues;
> + struct auxtrace_queue *queue;
> +
> + queue = &queues->queue_array[vpaq->queue_nr];
> + buffer = auxtrace_buffer__next(queue, buffer);
> +
> + if (!buffer)
> + return 0;
> +
> + vpaq->buffer = buffer;
> + vpaq->size = buffer->size;
> +
> + /* If the aux_buffer doesn't have data associated, try to load it */
> + if (!buffer->data) {
> + /* get the file desc associated with the perf data file */
> + int fd = perf_data__fd(vpaq->vpa->session->data);
> +
> + buffer->data = auxtrace_buffer__get_data(buffer, fd);
> + if (!buffer->data)
> + return -ENOMEM;
> + }
> +
> + vpaq->buf_len = buffer->size;
> +
> + if (buffer->size % dtl_entry_size)
> + vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size);
> +
> + if (vpaq->tb_buffer != buffer->buffer_nr) {
> + vpaq->pkt_len = 0;
> + vpaq->tb_buffer = 0;
> + }
> +
> + return 1;
> +}
> +
> +/*
> + * The first entry in the queue for VPA DTL PMU has the boot timebase,
> + * frequency details which are needed to get timestamp which is required to
> + * correlate with other events. Save the boot_tb and tb_freq as part of
> + * powerpc_vpadtl_queue. The very next entry is the actual trace data to
> + * be returned.
> + */
> +static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
> +{
> + int ret;
> + char *buf;
> + struct boottb_freq *boottb;
> +
> + ret = powerpc_vpadtl_get_buffer(vpaq);
> + if (ret <= 0)
> + return ret;
> +
> + boottb = (struct boottb_freq *)vpaq->buffer->data;
> + if (boottb->timebase == 0) {
> + vpaq->boot_tb = boottb->boot_tb;
> + vpaq->tb_freq = boottb->tb_freq;
> + vpaq->pkt_len += dtl_entry_size;
> + }
> +
> + buf = vpaq->buffer->data;
> + buf += vpaq->pkt_len;
> + vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
> +
> + vpaq->tb_buffer = vpaq->buffer->buffer_nr;
> + vpaq->buffer = NULL;
> + vpaq->buf_len = 0;
> +
> + return 1;
> +}
> +
> +static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
> + unsigned int queue_nr)
> +{
> + struct powerpc_vpadtl_queue *vpaq;
> +
> + vpaq = zalloc(sizeof(*vpaq));
> + if (!vpaq)
> + return NULL;
> +
> + vpaq->vpa = vpa;
> + vpaq->queue_nr = queue_nr;
> +
> + return vpaq;
> +}
> +
> +/*
> + * When the Dispatch Trace Log data is collected along with other events
> + * like sched tracepoint events, it needs to be correlated and present
> + * interleaved along with these events. Perf events can be collected
> + * parallely across the CPUs.
> + *
> + * An auxtrace_queue is created for each CPU. Data within each queue is in
> + * increasing order of timestamp. Allocate and setup auxtrace queues here.
> + * All auxtrace queues is maintained in auxtrace heap in the increasing order
> + * of timestamp. So always the lowest timestamp (entries to be processed first)
> + * is on top of the heap.
> + *
> + * To add to auxtrace heap, fetch the timestamp from first DTL entry
> + * for each of the queue.
> + */
> +static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa,
> + struct auxtrace_queue *queue,
> + unsigned int queue_nr)
> +{
> + struct powerpc_vpadtl_queue *vpaq = queue->priv;
> +
> + if (list_empty(&queue->head) || vpaq)
> + return 0;
> +
> + vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr);
> + if (!vpaq)
> + return -ENOMEM;
> +
> + queue->priv = vpaq;
> +
> + if (queue->cpu != -1)
> + vpaq->cpu = queue->cpu;
> +
> + if (!vpaq->on_heap) {
> + int ret;
> +retry:
> + ret = powerpc_vpadtl_decode(vpaq);
> + if (!ret)
> + return 0;
> +
> + if (ret < 0)
> + goto retry;
> +
> + vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq);
> +
> + ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp);
> + if (ret)
> + return ret;
> + vpaq->on_heap = true;
> + }
> +
> + return 0;
> +}
> +
> +static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < vpa->queues.nr_queues; i++) {
> + ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa)
> +{
> + if (vpa->queues.new_data) {
> + vpa->queues.new_data = false;
> + return powerpc_vpadtl__setup_queues(vpa);
> + }
> +
> + return 0;
> +}
> +
> static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
session is not __maybe_unused
> union perf_event *event __maybe_unused,
> - struct perf_sample *sample __maybe_unused,
> - const struct perf_tool *tool __maybe_unused)
> + struct perf_sample *sample,
> + const struct perf_tool *tool)
> {
> - return 0;
> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
> + int err = 0;
> +
> + if (dump_trace)
> + return 0;
> +
> + if (!tool->ordered_events) {
> + pr_err("VPA requires ordered events\n");
> + return -EINVAL;
> + }
> +
> + if (sample->time) {
> + err = powerpc_vpadtl__update_queues(vpa);
> + if (err)
> + return err;
> + }
> +
> + return err;
> }
>
> /*
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples
2025-09-15 7:27 ` [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples Athira Rajeev
@ 2025-09-15 15:08 ` Adrian Hunter
0 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2025-09-15 15:08 UTC (permalink / raw)
To: Athira Rajeev, acme, jolsa, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1,
venkat88
On 15/09/2025 10:27, Athira Rajeev wrote:
> Create samples from DTL entries for displaying in perf report
> and perf script. When the different PERF_RECORD_XX records are
> processed from perf session, powerpc_vpadtl_process_event() will
> be invoked. For each of the PERF_RECORD_XX record, compare the timestamp
> of perf record with timestamp of top element in the auxtrace heap.
> Process the auxtrace queue if the timestamp of element from heap is
> lower than timestamp from entry in perf record.
>
> Sometimes it could happen that one buffer is only partially
> processed. if the timestamp of occurrence of another event is more
> than currently processed element in the queue, it will move on
> to next perf record. So keep track of position of buffer to
> continue processing next time. Update the timestamp of the
> auxtrace heap with the timestamp of last processed entry from
> the auxtrace buffer.
>
> Generate perf sample for each entry in the dispatch trace log.
> Fill in the sample details:
> - sample ip is picked from srr0 field of dtl_entry
> - sample cpu is picked from processor_id of dtl_entry
> - sample id is from sample_id of powerpc_vpadtl
> - cpumode is set to PERF_RECORD_MISC_KERNEL
> - Additionally save the details in raw_data of sample. This
> is to print the relevant fields in perf_sample__fprintf_synth()
> when called from builtin-script
>
> The sample is processed by calling perf_session__deliver_synth_event()
> so that it gets included in perf report.
>
> Sample Output:
>
> ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.300 MB perf.data ]
>
> ./perf report
>
> # Samples: 321 of event 'vpa-dtl'
> # Event count (approx.): 321
> #
> # Children Self Command Shared Object Symbol
> # ........ ........ ....... ................. ..............................
> #
> 100.00% 100.00% swapper [kernel.kallsyms] [k] plpar_hcall_norets_notrace
>
> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
> ---
> Changelog:
> Addressed review comments from Adrian:
> - Moved time calculation to different function
> - Alignment and wording changes
>
> tools/perf/util/powerpc-vpadtl.c | 173 +++++++++++++++++++++++++++++++
> 1 file changed, 173 insertions(+)
>
> diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
> index 637abde60f44..dc437dae16b8 100644
> --- a/tools/perf/util/powerpc-vpadtl.c
> +++ b/tools/perf/util/powerpc-vpadtl.c
> @@ -161,6 +161,43 @@ static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char
> powerpc_vpadtl_dump(vpa, buf, len);
> }
>
> +/*
> + * Generate perf sample for each entry in the dispatch trace log.
> + * - sample ip is picked from srr0 field of powerpc_vpadtl_entry
> + * - sample cpu is logical cpu.
> + * - cpumode is set to PERF_RECORD_MISC_KERNEL
> + * - Additionally save the details in raw_data of sample. This
> + * is to print the relevant fields in perf_sample__fprintf_synth()
> + * when called from builtin-script
> + */
> +static int powerpc_vpadtl_sample(struct powerpc_vpadtl_entry *record, struct powerpc_vpadtl *vpa, u64 save, int cpu)
line length of 116 exceeds 100 columns
> +{
> + struct perf_sample sample;
> + union perf_event event;
> +
> + sample.ip = be64_to_cpu(record->srr0);
> + sample.period = 1;
> + sample.cpu = cpu;
> + sample.id = vpa->sample_id;
> + sample.callchain = NULL;
> + sample.branch_stack = NULL;
> + memset(&event, 0, sizeof(event));
> + sample.cpumode = PERF_RECORD_MISC_KERNEL;
> + sample.time = save;
> + sample.raw_data = record;
> + sample.raw_size = sizeof(record);
> + event.sample.header.type = PERF_RECORD_SAMPLE;
> + event.sample.header.misc = sample.cpumode;
> + event.sample.header.size = sizeof(struct perf_event_header);
> +
> + if (perf_session__deliver_synth_event(vpa->session, &event, &sample)) {
> + pr_debug("Failed to create sample for dtl entry\n");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
> {
> struct auxtrace_buffer *buffer = vpaq->buffer;
> @@ -234,6 +271,140 @@ static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
> return 1;
> }
>
> +static int powerpc_vpadtl_decode_all(struct powerpc_vpadtl_queue *vpaq)
> +{
> + int ret;
> + unsigned char *buf;
> +
> + if (!vpaq->buf_len || vpaq->pkt_len == vpaq->size) {
> + ret = powerpc_vpadtl_get_buffer(vpaq);
> + if (ret <= 0)
> + return ret;
> + }
> +
> + if (vpaq->buffer) {
> + buf = vpaq->buffer->data;
> + buf += vpaq->pkt_len;
> + vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
> + if ((long long)be64_to_cpu(vpaq->dtl->timebase) <= 0) {
> + if (vpaq->pkt_len != dtl_entry_size && vpaq->buf_len) {
> + vpaq->pkt_len += dtl_entry_size;
> + vpaq->buf_len -= dtl_entry_size;
> + }
> + return -1;
> + }
> + vpaq->pkt_len += dtl_entry_size;
> + vpaq->buf_len -= dtl_entry_size;
> + } else {
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static int powerpc_vpadtl_run_decoder(struct powerpc_vpadtl_queue *vpaq, u64 *timestamp)
> +{
> + struct powerpc_vpadtl *vpa = vpaq->vpa;
> + struct powerpc_vpadtl_entry *record;
> + int ret;
> + unsigned long long vpaq_timestamp;
> +
> + while (1) {
> + ret = powerpc_vpadtl_decode_all(vpaq);
> + if (!ret) {
> + pr_debug("All data in the queue has been processed.\n");
> + return 1;
> + }
> +
> + /*
> + * Error is detected when decoding VPA PMU trace. Continue to
> + * the next trace data and find out more dtl entries.
> + */
> + if (ret < 0)
> + continue;
> +
> + record = vpaq->dtl;
> +
> + vpaq_timestamp = powerpc_vpadtl_timestamp(vpaq);
> +
> + /* Update timestamp for the last record */
> + if (vpaq_timestamp > vpaq->timestamp)
> + vpaq->timestamp = vpaq_timestamp;
> +
> + /*
> + * If the timestamp of the queue is later than timestamp of the
> + * coming perf event, bail out so can allow the perf event to
> + * be processed ahead.
> + */
> + if (vpaq->timestamp >= *timestamp) {
> + *timestamp = vpaq->timestamp;
> + vpaq->pkt_len -= dtl_entry_size;
> + vpaq->buf_len += dtl_entry_size;
> + return 0;
> + }
> +
> + ret = powerpc_vpadtl_sample(record, vpa, vpaq_timestamp, vpaq->cpu);
> + if (ret)
> + continue;
> + }
> + return 0;
> +}
> +
> +/*
> + * For each of the PERF_RECORD_XX record, compare the timestamp
> + * of perf record with timestamp of top element in the auxtrace heap.
> + * Process the auxtrace queue if the timestamp of element from heap is
> + * lower than timestamp from entry in perf record.
> + *
> + * Update the timestamp of the auxtrace heap with the timestamp
> + * of last processed entry from the auxtrace buffer.
> + */
> +static int powerpc_vpadtl_process_queues(struct powerpc_vpadtl *vpa, u64 timestamp)
> +{
> + unsigned int queue_nr;
> + u64 ts;
> + int ret;
> +
> + while (1) {
> + struct auxtrace_queue *queue;
> + struct powerpc_vpadtl_queue *vpaq;
> +
> + if (!vpa->heap.heap_cnt)
> + return 0;
> +
> + if (vpa->heap.heap_array[0].ordinal >= timestamp)
> + return 0;
> +
> + queue_nr = vpa->heap.heap_array[0].queue_nr;
> + queue = &vpa->queues.queue_array[queue_nr];
> + vpaq = queue->priv;
> +
> + auxtrace_heap__pop(&vpa->heap);
> +
> + if (vpa->heap.heap_cnt) {
> + ts = vpa->heap.heap_array[0].ordinal + 1;
> + if (ts > timestamp)
> + ts = timestamp;
> + } else
> + ts = timestamp;
braces {} should be used on all arms of this statement
> +
> + ret = powerpc_vpadtl_run_decoder(vpaq, &ts);
> + if (ret < 0) {
> + auxtrace_heap__add(&vpa->heap, queue_nr, ts);
> + return ret;
> + }
> +
> + if (!ret) {
> + ret = auxtrace_heap__add(&vpa->heap, queue_nr, ts);
> + if (ret < 0)
> + return ret;
> + } else {
> + vpaq->on_heap = false;
> + }
> + }
> + return 0;
> +}
> +
> static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
> unsigned int queue_nr)
> {
> @@ -347,6 +518,8 @@ static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unu
> err = powerpc_vpadtl__update_queues(vpa);
> if (err)
> return err;
> +
> + err = powerpc_vpadtl_process_queues(vpa, sample->time);
> }
>
> return err;
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries
2025-09-15 7:27 ` [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries Athira Rajeev
@ 2025-09-15 15:09 ` Adrian Hunter
2025-09-16 4:38 ` Athira Rajeev
0 siblings, 1 reply; 18+ messages in thread
From: Adrian Hunter @ 2025-09-15 15:09 UTC (permalink / raw)
To: Athira Rajeev, acme, jolsa, maddy, irogers, namhyung,
linux-perf-users
Cc: linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1,
venkat88
On 15/09/2025 10:27, Athira Rajeev wrote:
> The process_event() function in "builtin-script.c" invokes
> perf_sample__fprintf_synth() for displaying PERF_TYPE_SYNTH
> type events.
>
> if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
> perf_sample__fprintf_synth(sample, evsel, fp);
>
> perf_sample__fprintf_synth() process the sample depending on the value
> in evsel->core.attr.config. Introduce perf_sample__fprintf_synth_vpadtl()
> and invoke this for PERF_SYNTH_POWERPC_VPA_DTL
>
> Sample output:
>
> ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.300 MB perf.data ]
>
> ./perf script
> perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
> migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
> migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
> migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
> swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
> swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>
> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
> ---
> Changelog:
> Addressed review comments from Adrian
> - Removed default callback and used perf_sample__fprintf_synth_vpadtl
> - fix build failure when using NO_AUXTRACE=1 by
> adding code around HAVE_AUXTRACE_SUPPORT
>
> tools/perf/builtin-script.c | 27 +++++++++++++++++++++++++++
> tools/perf/util/event.h | 3 +++
> 2 files changed, 30 insertions(+)
>
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index d9fbdcf72f25..8a03fdbfce5e 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -43,6 +43,7 @@
> #include <linux/stringify.h>
> #include <linux/time64.h>
> #include <linux/zalloc.h>
> +#include <linux/unaligned.h>
> #include <sys/utsname.h>
> #include "asm/bug.h"
> #include "util/mem-events.h"
> @@ -2003,6 +2004,30 @@ static int perf_sample__fprintf_synth_iflag_chg(struct perf_sample *sample, FILE
> return len + perf_sample__fprintf_pt_spacing(len, fp);
> }
>
> +#ifdef HAVE_AUXTRACE_SUPPORT
> +static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data, FILE *fp)
> +{
> + struct powerpc_vpadtl_entry *dtl = (struct powerpc_vpadtl_entry *)data->raw_data;
> +
> + fprintf(fp, "timebase: %" PRIu64 " dispatch_reason:%s, preempt_reason:%s,\n"
> + "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, waiting_to_ready_time:%d, processor_id: %d",\
Unnecessary line continuation, also line length exceeds 100 columns
> + get_unaligned_be64(&dtl->timebase),
> + dispatch_reasons[dtl->dispatch_reason],
> + preempt_reasons[dtl->preempt_reason],
> + be32_to_cpu(dtl->enqueue_to_dispatch_time),
> + be32_to_cpu(dtl->ready_to_enqueue_time),
> + be32_to_cpu(dtl->waiting_to_ready_time),
> + be16_to_cpu(dtl->processor_id));
> +
> + return 1;
Other __fprintf_*() are returning the number of char printed.
> +}
> +#else
> +static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data __maybe_unused, FILE *fp __maybe_unused)
> +{
> + return 0;
> +}
> +#endif
> +
> static int perf_sample__fprintf_synth(struct perf_sample *sample,
> struct evsel *evsel, FILE *fp)
> {
> @@ -2025,6 +2050,8 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,
> return perf_sample__fprintf_synth_evt(sample, fp);
> case PERF_SYNTH_INTEL_IFLAG_CHG:
> return perf_sample__fprintf_synth_iflag_chg(sample, fp);
> + case PERF_SYNTH_POWERPC_VPA_DTL:
> + return perf_sample__fprintf_synth_vpadtl(sample, fp);
> default:
> break;
> }
> diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
> index 7e0e58979e9c..64c63b59d617 100644
> --- a/tools/perf/util/event.h
> +++ b/tools/perf/util/event.h
> @@ -271,6 +271,9 @@ struct powerpc_vpadtl_entry {
> u64 srr1;
> };
>
> +extern const char *dispatch_reasons[11];
> +extern const char *preempt_reasons[10];
> +
> static inline void *perf_synth__raw_data(void *p)
> {
> return p + 4;
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
` (5 preceding siblings ...)
2025-09-15 7:27 ` [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries Athira Rajeev
@ 2025-09-15 16:07 ` Venkat
2025-09-18 6:31 ` Athira Rajeev
6 siblings, 1 reply; 18+ messages in thread
From: Venkat @ 2025-09-15 16:07 UTC (permalink / raw)
To: Athira Rajeev
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Adrian Hunter,
Madhavan Srinivasan, Ian Rogers, Namhyung Kim, linux-perf-users,
linuxppc-dev, aboorvad, sshegde, hbathini, Aditya.Bodkhe1
> On 15 Sep 2025, at 12:57 PM, Athira Rajeev <atrajeev@linux.ibm.com> wrote:
>
> The pseries Shared Processor Logical Partition(SPLPAR) machines can
> retrieve a log of dispatch and preempt events from the hypervisor
> using data from Disptach Trace Log(DTL) buffer. With this information,
> user can retrieve when and why each dispatch & preempt has occurred.
> The vpa-dtl PMU exposes the Virtual Processor Area(VPA) DTL counters
> via perf.
>
> - Patch 1 to 6 is perf tools side code changes to enable perf
> report/script on perf.data file
>
> Kernel and tools patches is separated. Kernel patches are posted here :
> https://lore.kernel.org/linux-perf-users/20250915072224.98958-1-atrajeev@linux.ibm.com/T/#t
>
> Infrastructure used
> ===================
>
> The VPA DTL PMU counters do not interrupt on overflow or generate any
> PMI interrupts. Therefore, hrtimer is used to poll the DTL data. The timer
> nterval can be provided by user via sample_period field in nano seconds.
> vpa dtl pmu has one hrtimer added per vpa-dtl pmu thread. DTL (Dispatch
> Trace Log) contains information about dispatch/preempt, enqueue time etc.
> We directly copy the DTL buffer data as part of auxiliary buffer and it
> will be processed later. This will avoid time taken to create samples
> in the kernel space. The PMU driver collecting Dispatch Trace Log (DTL)
> entries makes use of AUX support in perf infrastructure. On the tools side,
> this data is made available as PERF_RECORD_AUXTRACE records.
>
> To corelate each DTL entry with other events across CPU's, an auxtrace_queue
> is created for each CPU. Each auxtrace queue has a array/list of auxtrace buffers.
> All auxtrace queues is maintained in auxtrace heap. The queues are sorted
> based on timestamp. When the different PERF_RECORD_XX records are processed,
> compare the timestamp of perf record with timestamp of top element in the
> auxtrace heap so that DTL events can be co-related with other events
> Process the auxtrace queue if the timestamp of element from heap is
> lower than timestamp from entry in perf record. Sometimes it could happen that
> one buffer is only partially processed. if the timestamp of occurrence of
> another event is more than currently processed element in the queue, it will
> move on to next perf record. So keep track of position of buffer to continue
> processing next time. Update the timestamp of the auxtrace heap with the timestamp
> of last processed entry from the auxtrace buffer.
>
> This infrastructure ensures dispatch trace log entries can be corelated
> and presented along with other events like sched.
>
> vpa-dtl PMU example usage
>
> # ls /sys/devices/vpa_dtl/
> events format perf_event_mux_interval_ms power subsystem type uevent
>
>
> To capture the DTL data using perf record:
>
> # ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
>
> The result can be interpreted using perf report. Snippet of perf report -D:
>
> # ./perf report -D
>
> There are different PERF_RECORD_XX records. In that records corresponding to
> auxtrace buffers includes:
>
> 1. PERF_RECORD_AUX
> Conveys that new data is available in AUX area
>
> 2. PERF_RECORD_AUXTRACE_INFO
> Describes offset and size of auxtrace data in the buffers
>
> 3. PERF_RECORD_AUXTRACE
> This is the record that defines the auxtrace data which here in case of
> vpa-dtl pmu is dispatch trace log data.
>
> Snippet from perf report -D showing the PERF_RECORD_AUXTRACE dump
>
> 0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
> .
> . ... VPA DTL PMU data: size 1680 bytes, entries is 35
> . 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
> . 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
> . 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
> . 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
> . 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
> . 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
> . 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
> . 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
> . 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
>
> Above is representation of dtl entry of below format:
>
> struct dtl_entry {
> u8 dispatch_reason;
> u8 preempt_reason;
> u16 processor_id;
> u32 enqueue_to_dispatch_time;
> u32 ready_to_enqueue_time;
> u32 waiting_to_ready_time;
> u64 timebase;
> u64 fault_addr;
> u64 srr0;
> u64 srr1;
> };
>
> First two fields represent the dispatch reason and preempt reason. The post
> procecssing of PERF_RECORD_AUXTRACE records will translate to meaninful data
> for user to consume.
>
> Visualize the dispatch trace log entries with perf report:
> # ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.300 MB perf.data ]
>
> # ./perf report
> # Samples: 321 of event 'vpa-dtl'
> # Event count (approx.): 321
> #
> # Children Self Command Shared Object Symbol
> # ........ ........ ....... ................. ..............................
> #
> 100.00% 100.00% swapper [kernel.kallsyms] [k] plpar_hcall_norets_notrace
>
> Visualize the dispatch trace log entries with perf script:
>
> # ./perf script
> perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
> migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
> migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
> migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
> swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
> swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>
> Thanks
> Athira
>
> Athira Rajeev (6):
> tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
> tools/perf: process auxtrace events and display in perf report -D
> tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to
> present DTL samples
> tools/perf: Allocate and setup aux buffer queue to help co-relate with
> other events across CPU's
> tools/perf: Process the DTL entries in queue and deliver samples
> tools/perf: Enable perf script to present the DTL entries
>
> tools/perf/arch/powerpc/util/Build | 1 +
> tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++
> tools/perf/builtin-script.c | 27 +
> tools/perf/util/Build | 1 +
> tools/perf/util/auxtrace.c | 4 +
> tools/perf/util/auxtrace.h | 1 +
> tools/perf/util/event.h | 20 +
> tools/perf/util/powerpc-vpadtl.c | 732 ++++++++++++++++++++++++
> tools/perf/util/powerpc-vpadtl.h | 25 +
> 9 files changed, 925 insertions(+)
> create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
> create mode 100644 tools/perf/util/powerpc-vpadtl.c
> create mode 100644 tools/perf/util/powerpc-vpadtl.h
>
> --
> 2.47.1
>
Hello Athira,
Tested this patch set by applying on top of today’s mainline kernel, which was built by applying dtl enablement in PMU driver for PowerPC. Please refer below link for the patchiest
https://lore.kernel.org/all/20250915102947.26681-1-atrajeev@linux.ibm.com/
And this patchiest works as expected.
As a side note, if for some reason, you are resending this patch set, please correct the interval spelling in the cover page.
Please add below tag.
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Regards,
Venkat.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
2025-09-15 15:07 ` Adrian Hunter
@ 2025-09-16 4:37 ` Athira Rajeev
0 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-16 4:37 UTC (permalink / raw)
To: Adrian Hunter
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Madhavan Srinivasan,
Ian Rogers, Namhyung Kim, open list:PERFORMANCE EVENTS SUBSYSTEM,
linuxppc-dev, Aboorva Devarajan, Shrikanth Hegde, hbathini,
Aditya Bodkhe, Venkat Rao Bagalkote
> On 15 Sep 2025, at 8:37 PM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 15/09/2025 10:27, Athira Rajeev wrote:
>> The powerpc PMU collecting Dispatch Trace Log (DTL) entries makes use of
>> AUX support in perf infrastructure. The PMU driver has the functionality
>> to collect trace entries in the aux buffer. On the tools side, this data
>> is made available as PERF_RECORD_AUXTRACE records. This record is
>> generated by "perf record" command. To enable the creation of
>> PERF_RECORD_AUXTRACE, add functions to initialize auxtrace records ie
>> "auxtrace_record__init()". Fill in fields for other callbacks like
>> info_priv_size, info_fill, free, recording options etc. Define
>> auxtrace_type as PERF_AUXTRACE_VPA_DTL. Add header file to define vpa
>> dtl pmu specific details.
>>
>> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
>> ---
>> Changelog:
>> Addressed review comments from Adrian:
>> - Return VPADTL_AUXTRACE_PRIV_SIZE in powerpc_vpadtl_info_priv_size
>> - Remove unused powerpc_vpadtl_parse_snapshot_options
>> - Some of the function parameters had "__maybe_unused", corrected it.
>> - Used PERF_AUXTRACE_VPA_DTL instead of PERF_AUXTRACE_VPA_PMU
>> - Moved powerpc_vpadtl_process_auxtrace_info to next patch
>>
>> tools/perf/arch/powerpc/util/Build | 1 +
>> tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++++++++++++++++++++++
>> tools/perf/util/auxtrace.c | 1 +
>> tools/perf/util/auxtrace.h | 1 +
>> tools/perf/util/powerpc-vpadtl.h | 18 ++++
>> 5 files changed, 135 insertions(+)
>> create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
>> create mode 100644 tools/perf/util/powerpc-vpadtl.h
>>
>> diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
>> index fdd6a77a3432..a5b0babd307e 100644
>> --- a/tools/perf/arch/powerpc/util/Build
>> +++ b/tools/perf/arch/powerpc/util/Build
>> @@ -10,3 +10,4 @@ perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
>>
>> perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
>> perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>> +perf-util-$(CONFIG_AUXTRACE) += auxtrace.o
>> diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
>> new file mode 100644
>> index 000000000000..803c582c0c6f
>> --- /dev/null
>> +++ b/tools/perf/arch/powerpc/util/auxtrace.c
>> @@ -0,0 +1,114 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * VPA support
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/bitops.h>
>> +#include <linux/log2.h>
>
> Are bitops.h and log2.h needed?
>
>> +#include <linux/string.h>
>> +#include <time.h>
>> +
>> +#include "../../util/cpumap.h"
>
> Is cpumap.h needed?
>
>> +#include "../../util/evsel.h"
>> +#include "../../util/evlist.h"
>> +#include "../../util/session.h"
>> +#include "../../util/util.h"
>> +#include "../../util/pmu.h"
>
> Is pmu.h needed?
>
>> +#include "../../util/debug.h"
>> +#include "../../util/auxtrace.h"
>> +#include "../../util/powerpc-vpadtl.h"
>> +#include "../../util/record.h"
>> +#include <internal/lib.h> // page_size
>> +
>> +#define KiB(x) ((x) * 1024)
>> +
>> +static int
>> +powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
>> + struct evlist *evlist __maybe_unused,
>> + struct record_opts *opts)
>> +{
>> + opts->full_auxtrace = true;
>> +
>> + /*
>> + * Set auxtrace_mmap_pages to minimum
>> + * two pages
>> + */
>> + if (!opts->auxtrace_mmap_pages) {
>> + opts->auxtrace_mmap_pages = KiB(128) / page_size;
>> + if (opts->mmap_pages == UINT_MAX)
>> + opts->mmap_pages = KiB(256) / page_size;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
>> + struct evlist *evlist __maybe_unused)
>> +{
>> + return VPADTL_AUXTRACE_PRIV_SIZE;
>> +}
>> +
>> +static int
>> +powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
>> + struct perf_session *session __maybe_unused,
>> + struct perf_record_auxtrace_info *auxtrace_info,
>> + size_t priv_size __maybe_unused)
>> +{
>> + auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
>> +
>> + return 0;
>> +}
>> +
>> +static void powerpc_vpadtl_free(struct auxtrace_record *itr)
>> +{
>> + free(itr);
>> +}
>> +
>> +static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
>> +{
>> + return 0;
>> +}
>> +
>> +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
>> + int *err)
>> +{
>> + struct auxtrace_record *aux;
>> + struct evsel *pos;
>> + char *pmu_name;
>> + int found = 0;
>> +
>> + evlist__for_each_entry(evlist, pos) {
>> + pmu_name = strdup(pos->name);
>> + pmu_name = strtok(pmu_name, "/");
>> + if (strstarts(pmu_name, "vpa_dtl")) {
>
> pmu_name is leaked, but maybe it is not needed at all e.g.
>
> if (strstarts(pos->name, "vpa_dtl")) {
>
>> + found = 1;
>> + pos->needs_auxtrace_mmap = true;
>> + break;
>> + }
>> + }
>> +
>> + if (!found)
>> + return NULL;
>> +
>> + /*
>> + * To obtain the auxtrace buffer file descriptor, the auxtrace event
>> + * must come first.
>> + */
>> + evlist__to_front(pos->evlist, pos);
>> +
>> + aux = zalloc(sizeof(*aux));
>> + if (aux == NULL) {
>> + pr_debug("aux record is NULL\n");
>> + *err = -ENOMEM;
>> + return NULL;
>> + }
>> +
>> + aux->recording_options = powerpc_vpadtl_recording_options;
>> + aux->info_priv_size = powerpc_vpadtl_info_priv_size;
>> + aux->info_fill = powerpc_vpadtl_info_fill;
>> + aux->free = powerpc_vpadtl_free;
>> + aux->reference = powerpc_vpadtl_reference;
>> + return aux;
>> +}
>> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
>> index ebd32f1b8f12..f294658bb948 100644
>> --- a/tools/perf/util/auxtrace.c
>> +++ b/tools/perf/util/auxtrace.c
>> @@ -1393,6 +1393,7 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
>> case PERF_AUXTRACE_HISI_PTT:
>> err = hisi_ptt_process_auxtrace_info(event, session);
>> break;
>> + case PERF_AUXTRACE_VPA_DTL:
>> case PERF_AUXTRACE_UNKNOWN:
>> default:
>> return -EINVAL;
>> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
>> index f001cbb68f8e..e0a5b39fed12 100644
>> --- a/tools/perf/util/auxtrace.h
>> +++ b/tools/perf/util/auxtrace.h
>> @@ -50,6 +50,7 @@ enum auxtrace_type {
>> PERF_AUXTRACE_ARM_SPE,
>> PERF_AUXTRACE_S390_CPUMSF,
>> PERF_AUXTRACE_HISI_PTT,
>> + PERF_AUXTRACE_VPA_DTL,
>> };
>>
>> enum itrace_period_type {
>> diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
>> new file mode 100644
>> index 000000000000..50a7aa24acbe
>> --- /dev/null
>> +++ b/tools/perf/util/powerpc-vpadtl.h
>> @@ -0,0 +1,18 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * VPA DTL PMU Support
>> + */
>> +
>> +#ifndef INCLUDE__PERF_POWERPC_VPADTL_H__
>> +#define INCLUDE__PERF_POWERPC_VPADTL_H__
>> +
>> +#define POWERPC_VPADTL_NAME "powerpc_vpadtl_"
>
> Never used
Hi Adrian
Thanks for reviewing the patchset and sharing your comments
I will address these changes in V3
Thanks
Athira
>
>> +
>> +enum {
>> + POWERPC_VPADTL_TYPE,
>> + VPADTL_AUXTRACE_PRIV_MAX,
>> +};
>> +
>> +#define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
>> +
>> +#endif
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's
2025-09-15 15:08 ` Adrian Hunter
@ 2025-09-16 4:37 ` Athira Rajeev
0 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-16 4:37 UTC (permalink / raw)
To: Adrian Hunter
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Madhavan Srinivasan,
Ian Rogers, Namhyung Kim, open list:PERFORMANCE EVENTS SUBSYSTEM,
linuxppc-dev, Aboorva Devarajan, Shrikanth Hegde, hbathini,
Aditya Bodkhe, Venkat Rao Bagalkote
> On 15 Sep 2025, at 8:38 PM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 15/09/2025 10:27, Athira Rajeev wrote:
>> When the Dispatch Trace Log data is collected along with other events
>> like sched tracepoint events, it needs to be correlated and present
>> interleaved along with these events. Perf events can be collected
>> parallely across the CPUs. Hence it needs to be ensured events/dtl
>> entries are processed in timestamp order.
>>
>> An auxtrace_queue is created for each CPU. Data within each queue is in
>> increasing order of timestamp. Each auxtrace queue has a array/list of
>> auxtrace buffers. When processing the auxtrace buffer, the data is
>> mmapp'ed. All auxtrace queues is maintained in auxtrace heap. Each queue
>> has a queue number and a timestamp. The queues are sorted/added to head
>> based on the time stamp. So always the lowest timestamp (entries to be
>> processed first) is on top of the heap.
>>
>> The auxtrace queue needs to be allocated and heap needs to be populated
>> in the sorted order of timestamp. The queue needs to be filled with data
>> only once via powerpc_vpadtl__update_queues() function.
>> powerpc_vpadtl__setup_queues() iterates through all the entries to
>> allocate and setup the auxtrace queue. To add to auxtrace heap, it is
>> required to fetch the timebase of first entry for each of the queue.
>>
>> The first entry in the queue for VPA DTL PMU has the boot timebase,
>> frequency details which are needed to get timestamp which is required to
>> correlate with other events. The very next entry is the actual trace data
>> that provides timestamp for occurrence of DTL event. Formula used to get
>> the timestamp from dtl entry is:
>>
>> ((timbase from DTL entry - boot time) / frequency) * 1000000000
>>
>> powerpc_vpadtl_decode() adds the boot time and frequency as part of
>> powerpc_vpadtl_queue structure so that it can be reused. Each of the
>> dtl_entry is of 48 bytes size. Sometimes it could happen that one buffer
>> is only partially processed (if the timestamp of occurrence of another
>> event is more than currently processed element in queue, it will move on
>> to next event). In order to keep track of position of buffer, additional
>> fields is added to powerpc_vpadtl_queue structure.
>>
>> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
>> ---
>> Changelog:
>> Addressed review comments from Adrian
>> - Moved time calculation to separate function
>>
>> tools/perf/util/powerpc-vpadtl.c | 226 ++++++++++++++++++++++++++++++-
>> 1 file changed, 223 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
>> index 9098cbe00bfd..637abde60f44 100644
>> --- a/tools/perf/util/powerpc-vpadtl.c
>> +++ b/tools/perf/util/powerpc-vpadtl.c
>> @@ -10,6 +10,8 @@
>> #include "session.h"
>> #include "debug.h"
>> #include "powerpc-vpadtl.h"
>> +#include "sample.h"
>> +#include "tool.h"
>>
>> /*
>> * Structure to save the auxtrace queue
>> @@ -38,6 +40,14 @@ struct powerpc_vpadtl_queue {
>> struct auxtrace_buffer *buffer;
>> struct thread *thread;
>> bool on_heap;
>> + struct powerpc_vpadtl_entry *dtl;
>> + u64 timestamp;
>> + unsigned long pkt_len;
>> + unsigned long buf_len;
>> + u64 boot_tb;
>> + u64 tb_freq;
>> + unsigned int tb_buffer;
>> + unsigned int size;
>> bool done;
>> pid_t pid;
>> pid_t tid;
>> @@ -112,6 +122,33 @@ static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
>> }
>> }
>>
>> +static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq)
>> +{
>> + struct powerpc_vpadtl_entry *record = vpaq->dtl;
>> + double result, div;
>> + double boot_freq;
>> + unsigned long long boot_tb;
>> + unsigned long long diff;
>> + unsigned long long timestamp = 0;
>
> Prettier in descending line length e.g.
>
> struct powerpc_vpadtl_entry *record = vpaq->dtl;
> unsigned long long timestamp = 0;
> unsigned long long boot_tb;
> unsigned long long diff;
> double result, div;
> double boot_freq;
>
>> +
>> + /*
>> + * Formula used to get timestamp that can be co-related with
>> + * other perf events:
>> + * ((timbase from DTL entry - boot time) / frequency) * 1000000000
>> + */
>> + if (record->timebase) {
>> + boot_tb = vpaq->boot_tb;
>> + boot_freq = vpaq->tb_freq;
>> + diff = be64_to_cpu(record->timebase) - boot_tb;
>> + div = diff / boot_freq;
>> + result = div;
>> + result = result * 1000000000;
>> + timestamp = result;
>> + }
>> +
>> + return timestamp;
>> +}
>> +
>> static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
>> {
>> return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
>> @@ -124,12 +161,195 @@ static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char
>> powerpc_vpadtl_dump(vpa, buf, len);
>> }
>>
>> +static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
>> +{
>> + struct auxtrace_buffer *buffer = vpaq->buffer;
>> + struct auxtrace_queues *queues = &vpaq->vpa->queues;
>> + struct auxtrace_queue *queue;
>> +
>> + queue = &queues->queue_array[vpaq->queue_nr];
>> + buffer = auxtrace_buffer__next(queue, buffer);
>> +
>> + if (!buffer)
>> + return 0;
>> +
>> + vpaq->buffer = buffer;
>> + vpaq->size = buffer->size;
>> +
>> + /* If the aux_buffer doesn't have data associated, try to load it */
>> + if (!buffer->data) {
>> + /* get the file desc associated with the perf data file */
>> + int fd = perf_data__fd(vpaq->vpa->session->data);
>> +
>> + buffer->data = auxtrace_buffer__get_data(buffer, fd);
>> + if (!buffer->data)
>> + return -ENOMEM;
>> + }
>> +
>> + vpaq->buf_len = buffer->size;
>> +
>> + if (buffer->size % dtl_entry_size)
>> + vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size);
>> +
>> + if (vpaq->tb_buffer != buffer->buffer_nr) {
>> + vpaq->pkt_len = 0;
>> + vpaq->tb_buffer = 0;
>> + }
>> +
>> + return 1;
>> +}
>> +
>> +/*
>> + * The first entry in the queue for VPA DTL PMU has the boot timebase,
>> + * frequency details which are needed to get timestamp which is required to
>> + * correlate with other events. Save the boot_tb and tb_freq as part of
>> + * powerpc_vpadtl_queue. The very next entry is the actual trace data to
>> + * be returned.
>> + */
>> +static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
>> +{
>> + int ret;
>> + char *buf;
>> + struct boottb_freq *boottb;
>> +
>> + ret = powerpc_vpadtl_get_buffer(vpaq);
>> + if (ret <= 0)
>> + return ret;
>> +
>> + boottb = (struct boottb_freq *)vpaq->buffer->data;
>> + if (boottb->timebase == 0) {
>> + vpaq->boot_tb = boottb->boot_tb;
>> + vpaq->tb_freq = boottb->tb_freq;
>> + vpaq->pkt_len += dtl_entry_size;
>> + }
>> +
>> + buf = vpaq->buffer->data;
>> + buf += vpaq->pkt_len;
>> + vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
>> +
>> + vpaq->tb_buffer = vpaq->buffer->buffer_nr;
>> + vpaq->buffer = NULL;
>> + vpaq->buf_len = 0;
>> +
>> + return 1;
>> +}
>> +
>> +static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
>> + unsigned int queue_nr)
>> +{
>> + struct powerpc_vpadtl_queue *vpaq;
>> +
>> + vpaq = zalloc(sizeof(*vpaq));
>> + if (!vpaq)
>> + return NULL;
>> +
>> + vpaq->vpa = vpa;
>> + vpaq->queue_nr = queue_nr;
>> +
>> + return vpaq;
>> +}
>> +
>> +/*
>> + * When the Dispatch Trace Log data is collected along with other events
>> + * like sched tracepoint events, it needs to be correlated and present
>> + * interleaved along with these events. Perf events can be collected
>> + * parallely across the CPUs.
>> + *
>> + * An auxtrace_queue is created for each CPU. Data within each queue is in
>> + * increasing order of timestamp. Allocate and setup auxtrace queues here.
>> + * All auxtrace queues is maintained in auxtrace heap in the increasing order
>> + * of timestamp. So always the lowest timestamp (entries to be processed first)
>> + * is on top of the heap.
>> + *
>> + * To add to auxtrace heap, fetch the timestamp from first DTL entry
>> + * for each of the queue.
>> + */
>> +static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa,
>> + struct auxtrace_queue *queue,
>> + unsigned int queue_nr)
>> +{
>> + struct powerpc_vpadtl_queue *vpaq = queue->priv;
>> +
>> + if (list_empty(&queue->head) || vpaq)
>> + return 0;
>> +
>> + vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr);
>> + if (!vpaq)
>> + return -ENOMEM;
>> +
>> + queue->priv = vpaq;
>> +
>> + if (queue->cpu != -1)
>> + vpaq->cpu = queue->cpu;
>> +
>> + if (!vpaq->on_heap) {
>> + int ret;
>> +retry:
>> + ret = powerpc_vpadtl_decode(vpaq);
>> + if (!ret)
>> + return 0;
>> +
>> + if (ret < 0)
>> + goto retry;
>> +
>> + vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq);
>> +
>> + ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp);
>> + if (ret)
>> + return ret;
>> + vpaq->on_heap = true;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa)
>> +{
>> + unsigned int i;
>> + int ret;
>> +
>> + for (i = 0; i < vpa->queues.nr_queues; i++) {
>> + ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa)
>> +{
>> + if (vpa->queues.new_data) {
>> + vpa->queues.new_data = false;
>> + return powerpc_vpadtl__setup_queues(vpa);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
>
> session is not __maybe_unused
>
Sure
I will address these changes in V3
Thanks
Athira
>> union perf_event *event __maybe_unused,
>> - struct perf_sample *sample __maybe_unused,
>> - const struct perf_tool *tool __maybe_unused)
>> + struct perf_sample *sample,
>> + const struct perf_tool *tool)
>> {
>> - return 0;
>> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
>> + int err = 0;
>> +
>> + if (dump_trace)
>> + return 0;
>> +
>> + if (!tool->ordered_events) {
>> + pr_err("VPA requires ordered events\n");
>> + return -EINVAL;
>> + }
>> +
>> + if (sample->time) {
>> + err = powerpc_vpadtl__update_queues(vpa);
>> + if (err)
>> + return err;
>> + }
>> +
>> + return err;
>> }
>>
>> /*
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D
2025-09-15 15:08 ` Adrian Hunter
@ 2025-09-16 4:37 ` Athira Rajeev
0 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-16 4:37 UTC (permalink / raw)
To: Adrian Hunter
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Madhavan Srinivasan,
Ian Rogers, Namhyung Kim, open list:PERFORMANCE EVENTS SUBSYSTEM,
linuxppc-dev, Aboorva Devarajan, Shrikanth Hegde, hbathini,
Aditya Bodkhe, Venkat Rao Bagalkote
> On 15 Sep 2025, at 8:38 PM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 15/09/2025 10:27, Athira Rajeev wrote:
>> Add vpa dtl pmu auxtrace process function for "perf report -D".
>> The auxtrace event processing functions are defined in file
>> "util/powerpc-vpadtl.c". Data structures used includes "struct
>> powerpc_vpadtl_queue", "struct powerpc_vpadtl" to store the auxtrace
>> buffers in queue. Different PERF_RECORD_XXX are generated
>> during recording. PERF_RECORD_AUXTRACE_INFO is processed first
>> since it is of type perf_user_event_type and perf session event
>> delivers perf_session__process_user_event() first. Define function
>> powerpc_vpadtl_process_auxtrace_info() to handle the processing of
>> PERF_RECORD_AUXTRACE_INFO records. In this function, initialize
>> the aux buffer queues using auxtrace_queues__init(). Setup the
>> required infrastructure for aux data processing. The data is collected
>> per CPU and auxtrace_queue is created for each CPU.
>>
>> Define powerpc_vpadtl_process_event() function to process
>> PERF_RECORD_AUXTRACE records. In this, add the event to queue using
>> auxtrace_queues__add_event() and process the buffer in
>> powerpc_vpadtl_dump_event(). The first entry in the buffer with
>> timebase as zero has boot timebase and frequency. Remaining data is of
>> format for "struct powerpc_vpadtl_entry". Define the translation for
>> dispatch_reasons and preempt_reasons, report this when dump trace is
>> invoked via powerpc_vpadtl_dump()
>>
>> Sample output:
>>
>> ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
>> [ perf record: Woken up 1 times to write data ]
>> [ perf record: Captured and wrote 0.300 MB perf.data ]
>>
>> ./perf report -D
>>
>> 0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
>> .
>> . ... VPA DTL PMU data: size 1680 bytes, entries is 35
>> . 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
>> . 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
>> . 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
>> . 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
>> . 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
>> . 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
>> . 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
>> . 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
>> . 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
>>
>> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
>> ---
>> Changelog:
>> Addressed review comments from Adrian
>> - Renamed dtl_entry to powerpc_vpadtl_entry in util/event.h
>> - Removed unused #includes in powerpc-vpadtl.c
>> - Added helper session_to_vpa to get "struct powerpc_vpadtl"
>> - Updated auxtrace_queues__add_event only for piped data
>> - Used zfree to free "struct powerpc_vpadtl_queue"
>>
>> tools/perf/util/Build | 1 +
>> tools/perf/util/auxtrace.c | 3 +
>> tools/perf/util/event.h | 16 ++
>> tools/perf/util/powerpc-vpadtl.c | 263 +++++++++++++++++++++++++++++++
>> tools/perf/util/powerpc-vpadtl.h | 7 +
>> 5 files changed, 290 insertions(+)
>> create mode 100644 tools/perf/util/powerpc-vpadtl.c
>>
>> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
>> index 4959e7a990e4..5ead46dc98e7 100644
>> --- a/tools/perf/util/Build
>> +++ b/tools/perf/util/Build
>> @@ -136,6 +136,7 @@ perf-util-$(CONFIG_AUXTRACE) += arm-spe-decoder/
>> perf-util-$(CONFIG_AUXTRACE) += hisi-ptt.o
>> perf-util-$(CONFIG_AUXTRACE) += hisi-ptt-decoder/
>> perf-util-$(CONFIG_AUXTRACE) += s390-cpumsf.o
>> +perf-util-$(CONFIG_AUXTRACE) += powerpc-vpadtl.o
>>
>> ifdef CONFIG_LIBOPENCSD
>> perf-util-$(CONFIG_AUXTRACE) += cs-etm.o
>> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
>> index f294658bb948..6d10f3d61ff8 100644
>> --- a/tools/perf/util/auxtrace.c
>> +++ b/tools/perf/util/auxtrace.c
>> @@ -55,6 +55,7 @@
>> #include "hisi-ptt.h"
>> #include "s390-cpumsf.h"
>> #include "util/mmap.h"
>> +#include "powerpc-vpadtl.h"
>>
>> #include <linux/ctype.h>
>> #include "symbol/kallsyms.h"
>> @@ -1394,6 +1395,8 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
>> err = hisi_ptt_process_auxtrace_info(event, session);
>> break;
>> case PERF_AUXTRACE_VPA_DTL:
>> + err = powerpc_vpadtl_process_auxtrace_info(event, session);
>> + break;
>> case PERF_AUXTRACE_UNKNOWN:
>> default:
>> return -EINVAL;
>> diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
>> index e40d16d3246c..7ba208ae86fd 100644
>> --- a/tools/perf/util/event.h
>> +++ b/tools/perf/util/event.h
>> @@ -254,6 +254,22 @@ struct perf_synth_intel_iflag_chg {
>> u64 branch_ip; /* If via_branch */
>> };
>>
>> +/*
>> + * The powerpc VPA DTL entries are of below format
>> + */
>> +struct powerpc_vpadtl_entry {
>> + u8 dispatch_reason;
>> + u8 preempt_reason;
>> + u16 processor_id;
>> + u32 enqueue_to_dispatch_time;
>> + u32 ready_to_enqueue_time;
>> + u32 waiting_to_ready_time;
>> + u64 timebase;
>> + u64 fault_addr;
>> + u64 srr0;
>> + u64 srr1;
>> +};
>> +
>> static inline void *perf_synth__raw_data(void *p)
>> {
>> return p + 4;
>> diff --git a/tools/perf/util/powerpc-vpadtl.c b/tools/perf/util/powerpc-vpadtl.c
>> new file mode 100644
>> index 000000000000..2e8488a3dbd7
>> --- /dev/null
>> +++ b/tools/perf/util/powerpc-vpadtl.c
>> @@ -0,0 +1,263 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * VPA DTL PMU support
>> + */
>> +
>> +#include <inttypes.h>
>> +#include "color.h"
>> +#include "evlist.h"
>> +#include "session.h"
>
> Should really also:
>
> #include "auxtrace.h"
> #include "data.h"
> #include "machine.h"
>
>> +#include "debug.h"
>> +#include "powerpc-vpadtl.h"
>> +
>> +/*
>> + * Structure to save the auxtrace queue
>> + */
>> +struct powerpc_vpadtl {
>> + struct auxtrace auxtrace;
>> + struct auxtrace_queues queues;
>> + struct auxtrace_heap heap;
>> + u32 auxtrace_type;
>> + struct perf_session *session;
>> + struct machine *machine;
>> + u32 pmu_type;
>> +};
>> +
>> +struct boottb_freq {
>> + u64 boot_tb;
>> + u64 tb_freq;
>> + u64 timebase;
>> + u64 padded[3];
>> +};
>> +
>> +struct powerpc_vpadtl_queue {
>> + struct powerpc_vpadtl *vpa;
>> + unsigned int queue_nr;
>> + struct auxtrace_buffer *buffer;
>> + struct thread *thread;
>> + bool on_heap;
>> + bool done;
>> + pid_t pid;
>> + pid_t tid;
>> + int cpu;
>> +};
>> +
>> +const char *dispatch_reasons[11] = {
>> + "external_interrupt",
>> + "firmware_internal_event",
>> + "H_PROD",
>> + "decrementer_interrupt",
>> + "system_reset",
>> + "firmware_internal_event",
>> + "conferred_cycles",
>> + "time_slice",
>> + "virtual_memory_page_fault",
>> + "expropriated_adjunct",
>> + "priv_doorbell"};
>> +
>> +const char *preempt_reasons[10] = {
>> + "unused",
>> + "firmware_internal_event",
>> + "H_CEDE",
>> + "H_CONFER",
>> + "time_slice",
>> + "migration_hibernation_page_fault",
>> + "virtual_memory_page_fault",
>> + "H_CONFER_ADJUNCT",
>> + "hcall_adjunct",
>> + "HDEC_adjunct"};
>> +
>> +#define dtl_entry_size sizeof(struct powerpc_vpadtl_entry)
>> +
>> +/*
>> + * Function to dump the dispatch trace data when perf report
>> + * is invoked with -D
>> + */
>> +static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
>> + unsigned char *buf, size_t len)
>> +{
>> + struct powerpc_vpadtl_entry *dtl;
>> + int pkt_len, pos = 0;
>> + const char *color = PERF_COLOR_BLUE;
>> +
>> + color_fprintf(stdout, color,
>> + ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n",
>> + len, len/dtl_entry_size);
>> +
>> + if (len % dtl_entry_size)
>> + len = len - (len % dtl_entry_size);
>> +
>> + while (len) {
>> + pkt_len = dtl_entry_size;
>> + printf(".");
>> + color_fprintf(stdout, color, " %08x: ", pos);
>> + dtl = (struct powerpc_vpadtl_entry *)buf;
>> + if (dtl->timebase != 0) {
>> + printf("dispatch_reason:%s, preempt_reason:%s, enqueue_to_dispatch_time:%d,"
>> + "ready_to_enqueue_time:%d, waiting_to_ready_time:%d\n",
>> + dispatch_reasons[dtl->dispatch_reason], preempt_reasons[dtl->preempt_reason],\
>> + be32_to_cpu(dtl->enqueue_to_dispatch_time),\
>> + be32_to_cpu(dtl->ready_to_enqueue_time), be32_to_cpu(dtl->waiting_to_ready_time));
>
> Better if these lines were 100 columns or less
>
>> + } else {
>> + struct boottb_freq *boot_tb = (struct boottb_freq *)buf;
>> +
>> + printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n", boot_tb->boot_tb, boot_tb->tb_freq);
>
> Better if this lines was 100 columns or less
>
>
>> + }
>> +
>> + pos += pkt_len;
>> + buf += pkt_len;
>> + len -= pkt_len;
>> + }
>> +}
>> +
>> +static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
>> +{
>> + return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
>> +}
>> +
>> +static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf,
>> + size_t len)
>> +{
>> + printf(".\n");
>> + powerpc_vpadtl_dump(vpa, buf, len);
>> +}
>> +
>> +static int powerpc_vpadtl_process_event(struct perf_session *session __maybe_unused,
>> + union perf_event *event __maybe_unused,
>> + struct perf_sample *sample __maybe_unused,
>> + const struct perf_tool *tool __maybe_unused)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Process PERF_RECORD_AUXTRACE records
>> + */
>> +static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session,
>> + union perf_event *event,
>> + const struct perf_tool *tool __maybe_unused)
>> +{
>> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
>> + struct auxtrace_buffer *buffer;
>> + int fd = perf_data__fd(session->data);
>> + off_t data_offset;
>> + int err;
>> +
>> + if (!dump_trace)
>> + return 0;
>> +
>> + if (perf_data__is_pipe(session->data)) {
>> + data_offset = 0;
>> + } else {
>> + data_offset = lseek(fd, 0, SEEK_CUR);
>> + if (data_offset == -1)
>> + return -errno;
>> + }
>> +
>> + err = auxtrace_queues__add_event(&vpa->queues, session, event,
>> + data_offset, &buffer);
>> +
>> + if (err)
>> + return err;
>> +
>> + /* Dump here now we have copied a piped trace out of the pipe */
>> + if (auxtrace_buffer__get_data(buffer, fd)) {
>> + powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size);
>> + auxtrace_buffer__put_data(buffer);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused,
>> + const struct perf_tool *tool __maybe_unused)
>> +{
>> + return 0;
>> +}
>> +
>> +static void powerpc_vpadtl_free_events(struct perf_session *session)
>> +{
>> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
>> + struct auxtrace_queues *queues = &vpa->queues;
>> + struct powerpc_vpadtl_queue *vpaq;
>> +
>> + unsigned int i;
>> +
>> + for (i = 0; i < queues->nr_queues; i++) {
>
> Modern style allows int decl. inside for() e.g.
>
> for (int i = 0; i < queues->nr_queues; i++) {
>
>> + vpaq = queues->queue_array[i].priv;
>> + if (vpaq)
>> + zfree(&vpaq);
>
> free() can handle NULL, so vpaq not needed, just
>
> zfree(&queues->queue_array[i].priv);
Ok, got it
I will address these changes in V3
Thanks
Athira
>
>> + }
>> +
>> + auxtrace_queues__free(queues);
>> +}
>> +
>> +static void powerpc_vpadtl_free(struct perf_session *session)
>> +{
>> + struct powerpc_vpadtl *vpa = session_to_vpa(session);
>> +
>> + auxtrace_heap__free(&vpa->heap);
>> + powerpc_vpadtl_free_events(session);
>> + session->auxtrace = NULL;
>> + free(vpa);
>> +}
>> +
>> +static const char * const powerpc_vpadtl_info_fmts[] = {
>> + [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n",
>> +};
>> +
>> +static void powerpc_vpadtl_print_info(__u64 *arr)
>> +{
>> + if (!dump_trace)
>> + return;
>> +
>> + fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]);
>> +}
>> +
>> +/*
>> + * Process the PERF_RECORD_AUXTRACE_INFO records and setup
>> + * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO
>> + * is processed first since it is of type perf_user_event_type.
>> + * Initialise the aux buffer queues using auxtrace_queues__init().
>> + * auxtrace_queue is created for each CPU.
>> + */
>> +int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
>> + struct perf_session *session)
>> +{
>> + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
>> + size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE;
>> + struct powerpc_vpadtl *vpa;
>> + int err;
>> +
>> + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
>> + min_sz)
>> + return -EINVAL;
>> +
>> + vpa = zalloc(sizeof(struct powerpc_vpadtl));
>> + if (!vpa)
>> + return -ENOMEM;
>> +
>> + err = auxtrace_queues__init(&vpa->queues);
>> + if (err)
>> + goto err_free;
>> +
>> + vpa->session = session;
>> + vpa->machine = &session->machines.host; /* No kvm support */
>> + vpa->auxtrace_type = auxtrace_info->type;
>> + vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE];
>> +
>> + vpa->auxtrace.process_event = powerpc_vpadtl_process_event;
>> + vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event;
>> + vpa->auxtrace.flush_events = powerpc_vpadtl_flush;
>> + vpa->auxtrace.free_events = powerpc_vpadtl_free_events;
>> + vpa->auxtrace.free = powerpc_vpadtl_free;
>> + session->auxtrace = &vpa->auxtrace;
>> +
>> + powerpc_vpadtl_print_info(&auxtrace_info->priv[0]);
>> +
>> + return 0;
>> +
>> +err_free:
>> + free(vpa);
>> + return err;
>> +}
>> diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
>> index 50a7aa24acbe..aa76f5beac2c 100644
>> --- a/tools/perf/util/powerpc-vpadtl.h
>> +++ b/tools/perf/util/powerpc-vpadtl.h
>> @@ -15,4 +15,11 @@ enum {
>>
>> #define VPADTL_AUXTRACE_PRIV_SIZE (VPADTL_AUXTRACE_PRIV_MAX * sizeof(u64))
>>
>> +union perf_event;
>> +struct perf_session;
>> +struct perf_pmu;
>> +
>> +int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
>> + struct perf_session *session);
>> +
>> #endif
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries
2025-09-15 15:09 ` Adrian Hunter
@ 2025-09-16 4:38 ` Athira Rajeev
0 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-16 4:38 UTC (permalink / raw)
To: Adrian Hunter
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Madhavan Srinivasan,
Ian Rogers, Namhyung Kim, open list:PERFORMANCE EVENTS SUBSYSTEM,
linuxppc-dev, Aboorva Devarajan, Shrikanth Hegde, hbathini,
Aditya Bodkhe, Venkat Rao Bagalkote
> On 15 Sep 2025, at 8:39 PM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 15/09/2025 10:27, Athira Rajeev wrote:
>> The process_event() function in "builtin-script.c" invokes
>> perf_sample__fprintf_synth() for displaying PERF_TYPE_SYNTH
>> type events.
>>
>> if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH))
>> perf_sample__fprintf_synth(sample, evsel, fp);
>>
>> perf_sample__fprintf_synth() process the sample depending on the value
>> in evsel->core.attr.config. Introduce perf_sample__fprintf_synth_vpadtl()
>> and invoke this for PERF_SYNTH_POWERPC_VPA_DTL
>>
>> Sample output:
>>
>> ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
>> [ perf record: Woken up 1 times to write data ]
>> [ perf record: Captured and wrote 0.300 MB perf.data ]
>>
>> ./perf script
>> perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
>> migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
>> migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
>> migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
>> swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>> swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>>
>> Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
>> ---
>> Changelog:
>> Addressed review comments from Adrian
>> - Removed default callback and used perf_sample__fprintf_synth_vpadtl
>> - fix build failure when using NO_AUXTRACE=1 by
>> adding code around HAVE_AUXTRACE_SUPPORT
>>
>> tools/perf/builtin-script.c | 27 +++++++++++++++++++++++++++
>> tools/perf/util/event.h | 3 +++
>> 2 files changed, 30 insertions(+)
>>
>> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
>> index d9fbdcf72f25..8a03fdbfce5e 100644
>> --- a/tools/perf/builtin-script.c
>> +++ b/tools/perf/builtin-script.c
>> @@ -43,6 +43,7 @@
>> #include <linux/stringify.h>
>> #include <linux/time64.h>
>> #include <linux/zalloc.h>
>> +#include <linux/unaligned.h>
>> #include <sys/utsname.h>
>> #include "asm/bug.h"
>> #include "util/mem-events.h"
>> @@ -2003,6 +2004,30 @@ static int perf_sample__fprintf_synth_iflag_chg(struct perf_sample *sample, FILE
>> return len + perf_sample__fprintf_pt_spacing(len, fp);
>> }
>>
>> +#ifdef HAVE_AUXTRACE_SUPPORT
>> +static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data, FILE *fp)
>> +{
>> + struct powerpc_vpadtl_entry *dtl = (struct powerpc_vpadtl_entry *)data->raw_data;
>> +
>> + fprintf(fp, "timebase: %" PRIu64 " dispatch_reason:%s, preempt_reason:%s,\n"
>> + "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, waiting_to_ready_time:%d, processor_id: %d",\
>
> Unnecessary line continuation, also line length exceeds 100 columns
>
>> + get_unaligned_be64(&dtl->timebase),
>> + dispatch_reasons[dtl->dispatch_reason],
>> + preempt_reasons[dtl->preempt_reason],
>> + be32_to_cpu(dtl->enqueue_to_dispatch_time),
>> + be32_to_cpu(dtl->ready_to_enqueue_time),
>> + be32_to_cpu(dtl->waiting_to_ready_time),
>> + be16_to_cpu(dtl->processor_id));
>> +
>> + return 1;
>
> Other __fprintf_*() are returning the number of char printed.
Will send a V3 with this change
Thanks
Athira
>
>> +}
>> +#else
>> +static int perf_sample__fprintf_synth_vpadtl(struct perf_sample *data __maybe_unused, FILE *fp __maybe_unused)
>> +{
>> + return 0;
>> +}
>> +#endif
>> +
>> static int perf_sample__fprintf_synth(struct perf_sample *sample,
>> struct evsel *evsel, FILE *fp)
>> {
>> @@ -2025,6 +2050,8 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,
>> return perf_sample__fprintf_synth_evt(sample, fp);
>> case PERF_SYNTH_INTEL_IFLAG_CHG:
>> return perf_sample__fprintf_synth_iflag_chg(sample, fp);
>> + case PERF_SYNTH_POWERPC_VPA_DTL:
>> + return perf_sample__fprintf_synth_vpadtl(sample, fp);
>> default:
>> break;
>> }
>> diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
>> index 7e0e58979e9c..64c63b59d617 100644
>> --- a/tools/perf/util/event.h
>> +++ b/tools/perf/util/event.h
>> @@ -271,6 +271,9 @@ struct powerpc_vpadtl_entry {
>> u64 srr1;
>> };
>>
>> +extern const char *dispatch_reasons[11];
>> +extern const char *preempt_reasons[10];
>> +
>> static inline void *perf_synth__raw_data(void *p)
>> {
>> return p + 4;
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via
2025-09-15 16:07 ` [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Venkat
@ 2025-09-18 6:31 ` Athira Rajeev
0 siblings, 0 replies; 18+ messages in thread
From: Athira Rajeev @ 2025-09-18 6:31 UTC (permalink / raw)
To: Venkat
Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Adrian Hunter,
Madhavan Srinivasan, Ian Rogers, Namhyung Kim,
open list:PERFORMANCE EVENTS SUBSYSTEM, linuxppc-dev,
Aboorva Devarajan, Shrikanth Hegde, hbathini, Aditya Bodkhe
> On 15 Sep 2025, at 9:37 PM, Venkat <venkat88@linux.ibm.com> wrote:
>
>
>
>> On 15 Sep 2025, at 12:57 PM, Athira Rajeev <atrajeev@linux.ibm.com> wrote:
>>
>> The pseries Shared Processor Logical Partition(SPLPAR) machines can
>> retrieve a log of dispatch and preempt events from the hypervisor
>> using data from Disptach Trace Log(DTL) buffer. With this information,
>> user can retrieve when and why each dispatch & preempt has occurred.
>> The vpa-dtl PMU exposes the Virtual Processor Area(VPA) DTL counters
>> via perf.
>>
>> - Patch 1 to 6 is perf tools side code changes to enable perf
>> report/script on perf.data file
>>
>> Kernel and tools patches is separated. Kernel patches are posted here :
>> https://lore.kernel.org/linux-perf-users/20250915072224.98958-1-atrajeev@linux.ibm.com/T/#t
>>
>> Infrastructure used
>> ===================
>>
>> The VPA DTL PMU counters do not interrupt on overflow or generate any
>> PMI interrupts. Therefore, hrtimer is used to poll the DTL data. The timer
>> nterval can be provided by user via sample_period field in nano seconds.
>> vpa dtl pmu has one hrtimer added per vpa-dtl pmu thread. DTL (Dispatch
>> Trace Log) contains information about dispatch/preempt, enqueue time etc.
>> We directly copy the DTL buffer data as part of auxiliary buffer and it
>> will be processed later. This will avoid time taken to create samples
>> in the kernel space. The PMU driver collecting Dispatch Trace Log (DTL)
>> entries makes use of AUX support in perf infrastructure. On the tools side,
>> this data is made available as PERF_RECORD_AUXTRACE records.
>>
>> To corelate each DTL entry with other events across CPU's, an auxtrace_queue
>> is created for each CPU. Each auxtrace queue has a array/list of auxtrace buffers.
>> All auxtrace queues is maintained in auxtrace heap. The queues are sorted
>> based on timestamp. When the different PERF_RECORD_XX records are processed,
>> compare the timestamp of perf record with timestamp of top element in the
>> auxtrace heap so that DTL events can be co-related with other events
>> Process the auxtrace queue if the timestamp of element from heap is
>> lower than timestamp from entry in perf record. Sometimes it could happen that
>> one buffer is only partially processed. if the timestamp of occurrence of
>> another event is more than currently processed element in the queue, it will
>> move on to next perf record. So keep track of position of buffer to continue
>> processing next time. Update the timestamp of the auxtrace heap with the timestamp
>> of last processed entry from the auxtrace buffer.
>>
>> This infrastructure ensures dispatch trace log entries can be corelated
>> and presented along with other events like sched.
>>
>> vpa-dtl PMU example usage
>>
>> # ls /sys/devices/vpa_dtl/
>> events format perf_event_mux_interval_ms power subsystem type uevent
>>
>>
>> To capture the DTL data using perf record:
>>
>> # ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
>>
>> The result can be interpreted using perf report. Snippet of perf report -D:
>>
>> # ./perf report -D
>>
>> There are different PERF_RECORD_XX records. In that records corresponding to
>> auxtrace buffers includes:
>>
>> 1. PERF_RECORD_AUX
>> Conveys that new data is available in AUX area
>>
>> 2. PERF_RECORD_AUXTRACE_INFO
>> Describes offset and size of auxtrace data in the buffers
>>
>> 3. PERF_RECORD_AUXTRACE
>> This is the record that defines the auxtrace data which here in case of
>> vpa-dtl pmu is dispatch trace log data.
>>
>> Snippet from perf report -D showing the PERF_RECORD_AUXTRACE dump
>>
>> 0 0 0x39b10 [0x30]: PERF_RECORD_AUXTRACE size: 0x690 offset: 0 ref: 0 idx: 0 tid: -1 cpu: 0
>> .
>> . ... VPA DTL PMU data: size 1680 bytes, entries is 35
>> . 00000000: boot_tb: 21349649546353231, tb_freq: 512000000
>> . 00000030: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:7064, ready_to_enqueue_time:187, waiting_to_ready_time:6611773
>> . 00000060: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:146, ready_to_enqueue_time:0, waiting_to_ready_time:15359437
>> . 00000090: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:4868, ready_to_enqueue_time:232, waiting_to_ready_time:5100709
>> . 000000c0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:179, ready_to_enqueue_time:0, waiting_to_ready_time:30714243
>> . 000000f0: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:197, ready_to_enqueue_time:0, waiting_to_ready_time:15350648
>> . 00000120: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:213, ready_to_enqueue_time:0, waiting_to_ready_time:15353446
>> . 00000150: dispatch_reason:priv doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:212, ready_to_enqueue_time:0, waiting_to_ready_time:15355126
>> . 00000180: dispatch_reason:decrementer interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:6368, ready_to_enqueue_time:164, waiting_to_ready_time:5104665
>>
>> Above is representation of dtl entry of below format:
>>
>> struct dtl_entry {
>> u8 dispatch_reason;
>> u8 preempt_reason;
>> u16 processor_id;
>> u32 enqueue_to_dispatch_time;
>> u32 ready_to_enqueue_time;
>> u32 waiting_to_ready_time;
>> u64 timebase;
>> u64 fault_addr;
>> u64 srr0;
>> u64 srr1;
>> };
>>
>> First two fields represent the dispatch reason and preempt reason. The post
>> procecssing of PERF_RECORD_AUXTRACE records will translate to meaninful data
>> for user to consume.
>>
>> Visualize the dispatch trace log entries with perf report:
>> # ./perf record -a -e sched:*,vpa_dtl/dtl_all/ -c 1000000000 sleep 1
>> [ perf record: Woken up 1 times to write data ]
>> [ perf record: Captured and wrote 0.300 MB perf.data ]
>>
>> # ./perf report
>> # Samples: 321 of event 'vpa-dtl'
>> # Event count (approx.): 321
>> #
>> # Children Self Command Shared Object Symbol
>> # ........ ........ ....... ................. ..............................
>> #
>> 100.00% 100.00% swapper [kernel.kallsyms] [k] plpar_hcall_norets_notrace
>>
>> Visualize the dispatch trace log entries with perf script:
>>
>> # ./perf script
>> perf 13322 [002] 233.835807: sched:sched_switch: perf:13322 [120] R ==> migration/2:27 [0]
>> migration/2 27 [002] 233.835811: sched:sched_migrate_task: comm=perf pid=13322 prio=120 orig_cpu=2 dest_cpu=3
>> migration/2 27 [002] 233.835818: sched:sched_stat_runtime: comm=migration/2 pid=27 runtime=9214 [ns]
>> migration/2 27 [002] 233.835819: sched:sched_switch: migration/2:27 [0] S ==> swapper/2:0 [120]
>> swapper 0 [002] 233.835822: vpa-dtl: timebase: 338954486062657 dispatch_reason:decrementer_interrupt, preempt_reason:H_CEDE, enqueue_to_dispatch_time:435, ready_to_enqueue_time:0, waiting_to_ready_time:34775058, processor_id: 202 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>> swapper 0 [001] 233.835886: vpa-dtl: timebase: 338954486095398 dispatch_reason:priv_doorbell, preempt_reason:H_CEDE, enqueue_to_dispatch_time:542, ready_to_enqueue_time:0, waiting_to_ready_time:1245360, processor_id: 201 c0000000000f8094 plpar_hcall_norets_notrace+0x18 ([kernel.kallsyms])
>>
>> Thanks
>> Athira
>>
>> Athira Rajeev (6):
>> tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc
>> tools/perf: process auxtrace events and display in perf report -D
>> tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to
>> present DTL samples
>> tools/perf: Allocate and setup aux buffer queue to help co-relate with
>> other events across CPU's
>> tools/perf: Process the DTL entries in queue and deliver samples
>> tools/perf: Enable perf script to present the DTL entries
>>
>> tools/perf/arch/powerpc/util/Build | 1 +
>> tools/perf/arch/powerpc/util/auxtrace.c | 114 ++++
>> tools/perf/builtin-script.c | 27 +
>> tools/perf/util/Build | 1 +
>> tools/perf/util/auxtrace.c | 4 +
>> tools/perf/util/auxtrace.h | 1 +
>> tools/perf/util/event.h | 20 +
>> tools/perf/util/powerpc-vpadtl.c | 732 ++++++++++++++++++++++++
>> tools/perf/util/powerpc-vpadtl.h | 25 +
>> 9 files changed, 925 insertions(+)
>> create mode 100644 tools/perf/arch/powerpc/util/auxtrace.c
>> create mode 100644 tools/perf/util/powerpc-vpadtl.c
>> create mode 100644 tools/perf/util/powerpc-vpadtl.h
>>
>> --
>> 2.47.1
>>
>
> Hello Athira,
>
> Tested this patch set by applying on top of today’s mainline kernel, which was built by applying dtl enablement in PMU driver for PowerPC. Please refer below link for the patchiest
>
> https://lore.kernel.org/all/20250915102947.26681-1-atrajeev@linux.ibm.com/
>
> And this patchiest works as expected.
>
> As a side note, if for some reason, you are resending this patch set, please correct the interval spelling in the cover page.
>
>
> Please add below tag.
>
> Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
>
> Regards,
> Venkat.
Thanks Venkat for testing the patch series
Athira
>
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-09-18 6:32 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-15 7:27 [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 1/6] tools/perf: Add basic CONFIG_AUXTRACE support for VPA pmu on powerpc Athira Rajeev
2025-09-15 15:07 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 2/6] tools/perf: process auxtrace events and display in perf report -D Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 3/6] tools/perf: Add event name as vpa-dtl of PERF_TYPE_SYNTH type to present DTL samples Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 4/6] tools/perf: Allocate and setup aux buffer queue to help co-relate with other events across CPU's Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-16 4:37 ` Athira Rajeev
2025-09-15 7:27 ` [PATCH V2 5/6] tools/perf: Process the DTL entries in queue and deliver samples Athira Rajeev
2025-09-15 15:08 ` Adrian Hunter
2025-09-15 7:27 ` [PATCH V2 6/6] tools/perf: Enable perf script to present the DTL entries Athira Rajeev
2025-09-15 15:09 ` Adrian Hunter
2025-09-16 4:38 ` Athira Rajeev
2025-09-15 16:07 ` [PATCH V2 0/6] perf/tools: Add interface to expose vpa dtl counters via Venkat
2025-09-18 6:31 ` Athira Rajeev
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).