Add htm pmu auxtrace process function for "perf script -D". The auxtrace event processing functions are defined in file "util/powerpc-htm.c". 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_htm_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 trace data which is part of each AUXTRACE record will be written to a file named htm.bin.n<nodeindex>.p<nodalchipindex>.c<coreindexonchip> Sample output: # perf record -C 8 -m,256 -e htm/event=0x901032/ ls [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 2048.915 MB perf.data ] # perf script -D -i perf.data . ... HTM PMU data: size <N> bytes # 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 ] Signed-off-by: Athira Rajeev <[email protected]> --- tools/perf/arch/powerpc/util/htm.c | 3 + tools/perf/util/auxtrace.c | 4 + tools/perf/util/auxtrace.h | 1 + tools/perf/util/powerpc-htm.c | 149 +++++++++++++++++++++++++++++ tools/perf/util/powerpc-htm.h | 2 + 5 files changed, 159 insertions(+) diff --git a/tools/perf/arch/powerpc/util/htm.c b/tools/perf/arch/powerpc/util/htm.c index cc733f45ac9b..0e6638c02716 100644 --- a/tools/perf/arch/powerpc/util/htm.c +++ b/tools/perf/arch/powerpc/util/htm.c @@ -56,6 +56,7 @@ htm_recording_options(struct auxtrace_record *ar __maybe_unused, if (strstarts(pos->name, "htm")) { pos->needs_auxtrace_mmap = true; pos->core.attr.aux_watermark = opts->auxtrace_mmap_pages * (size_t)page_size; + pos->core.attr.sample_type |= PERF_SAMPLE_RAW; break; } } @@ -75,6 +76,8 @@ htm_info_fill(struct auxtrace_record *itr __maybe_unused, struct perf_record_auxtrace_info *auxtrace_info __maybe_unused, size_t priv_size __maybe_unused) { + auxtrace_info->type = PERF_AUXTRACE_POWERPC_HTM; + return 0; } diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 0b851f32e98c..9f32f54fad43 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -56,6 +56,7 @@ #include "s390-cpumsf.h" #include "util/mmap.h" #include "powerpc-vpadtl.h" +#include "powerpc-htm.h" #include <linux/ctype.h> #include "symbol/kallsyms.h" @@ -1427,6 +1428,9 @@ int perf_event__process_auxtrace_info(const struct perf_tool *tool __maybe_unuse case PERF_AUXTRACE_VPA_DTL: err = powerpc_vpadtl_process_auxtrace_info(event, session); break; + case PERF_AUXTRACE_POWERPC_HTM: + err = powerpc_htm_process_auxtrace_info(event, session); + break; case PERF_AUXTRACE_UNKNOWN: default: return -EINVAL; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 6947f3f284c0..68b17802a419 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -46,6 +46,7 @@ enum auxtrace_type { PERF_AUXTRACE_S390_CPUMSF, PERF_AUXTRACE_HISI_PTT, PERF_AUXTRACE_VPA_DTL, + PERF_AUXTRACE_POWERPC_HTM, }; enum itrace_period_type { diff --git a/tools/perf/util/powerpc-htm.c b/tools/perf/util/powerpc-htm.c index 5043ff41a609..ffddf0e59fc1 100644 --- a/tools/perf/util/powerpc-htm.c +++ b/tools/perf/util/powerpc-htm.c @@ -9,6 +9,24 @@ #include "session.h" #include "debug.h" #include <internal/xyarray.h> +#include <linux/string.h> +#include "color.h" +#include <inttypes.h> +#include "powerpc-htm.h" +#include <errno.h> + +struct perf_session; + +struct powerpc_htm { + struct auxtrace auxtrace; + struct auxtrace_queues queues; + struct auxtrace_heap heap; + u32 auxtrace_type; + struct perf_session *session; + struct machine *machine; + u32 pmu_type; + char htmbin_file[64]; +}; /* * Check if HTM events have more data to collect. @@ -72,3 +90,134 @@ int arch_perf_record__need_read(struct evlist *evlist) return 1; } + +static void powerpc_htm_dump_event(size_t len) +{ + const char *color = PERF_COLOR_BLUE; + + color_fprintf(stdout, color, + ". ... HTM PMU data: size %zu bytes\n", + len); +} + +static int powerpc_htm_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; +} + +static int powerpc_htm_process_auxtrace_event(struct perf_session *session __maybe_unused, + union perf_event *event, + const struct perf_tool *tool __maybe_unused) +{ + powerpc_htm_dump_event(event->auxtrace.size); + + return 0; +} + +static int powerpc_htm_flush(struct perf_session *session __maybe_unused, + const struct perf_tool *tool __maybe_unused) +{ + return 0; +} + +static void powerpc_htm_free_events(struct perf_session *session) +{ + struct powerpc_htm *htm = container_of(session->auxtrace, struct powerpc_htm, + auxtrace); + struct auxtrace_queues *queues = &htm->queues; + unsigned int i; + + for (i = 0; i < queues->nr_queues; i++) + zfree(&queues->queue_array[i].priv); + + auxtrace_queues__free(queues); +} + +static void powerpc_htm_free(struct perf_session *session) +{ + struct powerpc_htm *htm = container_of(session->auxtrace, struct powerpc_htm, + auxtrace); + + powerpc_htm_free_events(session); + session->auxtrace = NULL; + free(htm); +} +static const char * const powerpc_htm_info_fmts[] = { + [POWERPC_HTM_TYPE] = " PMU Type %"PRId64"\n", +}; + +static void powerpc_htm_print_info(__u64 *arr) +{ + if (!dump_trace) + return; + + fprintf(stdout, powerpc_htm_info_fmts[POWERPC_HTM_TYPE], arr[POWERPC_HTM_TYPE]); +} + +int powerpc_htm_process_auxtrace_info(union perf_event *event, + struct perf_session *session) +{ + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; + struct evsel *evsel = evlist__event2evsel(session->evlist, event); + u32 nodeindex, nodalchipindex, coreindexonchip; + int config = (evsel->core.attr.config); + size_t min_sz = sizeof(u64) * POWERPC_HTM_TYPE; + struct powerpc_htm *htm; + int err; + FILE *fp; + + nodeindex = (config >> 4) & 0xff; + nodalchipindex = (config >> 12) & 0xff; + coreindexonchip = (config >> 20) & 0xff; + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + + min_sz) + return -EINVAL; + + htm = zalloc(sizeof(struct powerpc_htm)); + if (!htm) + return -ENOMEM; + + err = auxtrace_queues__init(&htm->queues); + if (err) + goto err_free; + + htm->session = session; + htm->machine = &session->machines.host; /* No kvm support */ + htm->auxtrace_type = auxtrace_info->type; + htm->pmu_type = auxtrace_info->priv[POWERPC_HTM_TYPE]; + + htm->auxtrace.process_event = powerpc_htm_process_event; + htm->auxtrace.process_auxtrace_event = powerpc_htm_process_auxtrace_event; + htm->auxtrace.flush_events = powerpc_htm_flush; + htm->auxtrace.free_events = powerpc_htm_free_events; + htm->auxtrace.free = powerpc_htm_free; + session->auxtrace = &htm->auxtrace; + + snprintf(htm->htmbin_file, sizeof(htm->htmbin_file), "htm.bin.n%d.p%d.c%d", nodeindex, nodalchipindex, coreindexonchip); + fp = fopen(htm->htmbin_file, "w"); + if (!fp) { + pr_err("Failed to create %s: %s\n", htm->htmbin_file, strerror(errno)); + return -errno; + } + fclose(fp); + + powerpc_htm_print_info(&auxtrace_info->priv[0]); + + err = auxtrace_queues__process_index(&htm->queues, session); + if (err) + goto err_free_queues; + + return 0; + +err_free_queues: + auxtrace_queues__free(&htm->queues); + session->auxtrace = NULL; + +err_free: + free(htm); + return err; +} diff --git a/tools/perf/util/powerpc-htm.h b/tools/perf/util/powerpc-htm.h index be7f8c03e161..0dc31fa252b4 100644 --- a/tools/perf/util/powerpc-htm.h +++ b/tools/perf/util/powerpc-htm.h @@ -20,4 +20,6 @@ struct perf_session; struct perf_pmu; struct auxtrace_record *htm_recording_init(struct evsel *pos); +int powerpc_htm_process_auxtrace_info(union perf_event *event, + struct perf_session *session); #endif -- 2.52.0
