[PATCH 8/9] tools/perf/powerpc: Add event name as htm of PERF_TYPE_SYNTH type to present htm samples
From: Athira Rajeev <hidden>
Date: 2026-07-01 08:42:04
Also in:
linux-perf-users
Subsystem:
performance events subsystem, the rest · Maintainers:
Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Linus Torvalds
HTM trace details are captured as-is in PERF_RECORD_AUXTRACE
records. To present htm entries as samples, create an event
with name as "htm" and type PERF_TYPE_SYNTH.
Add perf_synth_id, "PERF_SYNTH_POWERPC_HTM" as config value for the
event. Create a sample id to be a fixed offset from evsel id.
Invoke powerpc_htm_create_sample() using the logical address
as sample ip.
This will help in understanding hot logical address from the
traces.
Usage:
# perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ -o perf_1.data ls 1>out
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 257.504 MB perf_1.data ]
# ./perf report -i perf_1.data
# Samples: 8M of event 'htm'
# Event count (approx.): 8515199
#
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................ ......................
#
0.61% 0.61% swapper [unknown] [.] 0x00000006fd567fe0
0.33% 0.33% swapper [unknown] [.] 0x00000006fc194b20
0.20% 0.20% swapper [unknown] [.] 0x0000000066113f80
0.18% 0.18% swapper [unknown] [.] 0x00000007fd888f20
0.15% 0.15% swapper [unknown] [.] 0x00000006fd567fc0
0.08% 0.08% swapper [unknown] [.] 0x00000006fc194b00
0.05% 0.05% swapper [unknown] [.] 0x00000007fd888f00
0.03% 0.03% swapper [unknown] [.] 0x0000000422510700
0.03% 0.03% swapper [unknown] [.] 0x0000000422510820
0.03% 0.03% swapper [unknown] [.] 0x00000007fd888b80
0.02% 0.02% swapper [unknown] [.] 0x000000000a0ece40
0.02% 0.02% swapper [unknown] [.] 0x000000000a0ed2e0
0.01% 0.01% swapper [unknown] [.] 0x00000007fd888c40
0.01% 0.01% swapper [unknown] [.] 0x00000007fd889000
0.01% 0.01% swapper [unknown] [.] 0x00000007fd5bc200
0.01% 0.01% swapper [unknown] [.] 0x00000007fd61c200
0.01% 0.01% swapper [unknown] [.] 0x00000007fd28c200
0.01% 0.01% swapper [unknown] [.] 0x00000007fd22c200
0.01% 0.01% swapper [unknown] [.] 0x00000007fd1fc200
Signed-off-by: Athira Rajeev <redacted>
---
tools/perf/util/event.h | 1 +
tools/perf/util/powerpc-htm.c | 110 +++++++++++++++++++++++++++++++++-
2 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2ea83fdf8a03..f5aa7eb9f5b7 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h@@ -118,6 +118,7 @@ enum perf_synth_id { PERF_SYNTH_INTEL_EVT, PERF_SYNTH_INTEL_IFLAG_CHG, PERF_SYNTH_POWERPC_VPA_DTL, + PERF_SYNTH_POWERPC_HTM, }; /*
diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c
index 83253850870c..050fbceac71e 100644
--- a/tools/perf/util/powerpc-htm.c
+++ b/tools/perf/util/powerpc-htm.c@@ -42,6 +42,7 @@ struct powerpc_htm { char trans_file[64]; int htm_mem_entries; int mem_maps; + u64 sample_id; }; struct htm_mem {
@@ -128,6 +129,43 @@ static int run_htmdecode(const char *input_file, const char *output_file) return 0; } +static int powerpc_htm_create_sample(unsigned long addr, struct perf_session *session, + struct powerpc_htm *htm) +{ + struct perf_sample sample; + union perf_event event; + + if (dump_trace) + return 0; + + memset(&sample, 0, sizeof(sample)); + sample.cpumode = PERF_RECORD_MISC_USER; + + if (!addr) + return 0; + + if (addr >= 0xc000000000000000) + sample.cpumode = PERF_RECORD_MISC_KERNEL; + + sample.ip = addr; + sample.period = 1; + sample.cpu = 0; + sample.id = htm->sample_id; + sample.callchain = NULL; + sample.branch_stack = NULL; + memset(&event, 0, sizeof(event)); + 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(session, &event, &sample)) { + pr_debug("Failed to create sample for htm entry\n"); + return -1; + } + + return 0; +} + static void *safe_realloc(void *ptr, size_t new_size) { void *tmp = realloc(ptr, new_size);
@@ -309,7 +347,7 @@ static struct addr_map *process_trace_file(const char *trace_file, return maps; } -static int create_mem_maps(struct powerpc_htm *htm) +static int create_mem_maps(struct perf_session *session, struct powerpc_htm *htm) { off_t file_size; void *htmdata, *mapped_data;
@@ -422,6 +460,7 @@ static int create_mem_maps(struct powerpc_htm *htm) maps[i].event, maps[i].phys_addr, (unsigned long)maps[i].logical_addr); + powerpc_htm_create_sample(maps[i].logical_addr, session, htm); } free(maps);
@@ -581,7 +620,7 @@ static int powerpc_htm_process_event(struct perf_session *session __maybe_unused } /* Only for power bus traces, we decode traces */ if (config == 1) - create_mem_maps(htm); + create_mem_maps(session, htm); } return 0;
@@ -636,6 +675,69 @@ static void powerpc_htm_print_info(__u64 *arr) fprintf(stdout, powerpc_htm_info_fmts[POWERPC_HTM_TYPE], arr[POWERPC_HTM_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); + if (!evsel->name) { + pr_err("Failed to allocate memory for event name\n"); + return; + } + break; + } + } +} + +static int +powerpc_htm_synth_events(struct powerpc_htm *htm, 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, "htm")) { + found = true; + break; + } + } + + if (!found) { + pr_debug("No selected events with HTM 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_HTM; + + /* 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; + + htm->sample_id = id; + set_event_name(evlist, id, "htm"); + + return 0; +} + int powerpc_htm_process_auxtrace_info(union perf_event *event, struct perf_session *session) {
@@ -698,6 +800,10 @@ int powerpc_htm_process_auxtrace_info(union perf_event *event, if (err) goto err_free_queues; + err = powerpc_htm_synth_events(htm, session); + if (err) + goto err_free; + return 0; err_free_queues:
--
2.52.0