perf tools: display the new PERF_RECORD_BPF_METADATA event
authorBlake Jones <blakejones@google.com>
Thu, 12 Jun 2025 19:49:38 +0000 (12:49 -0700)
committerNamhyung Kim <namhyung@kernel.org>
Fri, 20 Jun 2025 21:48:56 +0000 (14:48 -0700)
Here's some example "perf script -D" output for the new event type. The
": unhandled!" message is from tool.c, analogous to other behavior there.
I've elided some rows with all NUL characters for brevity, and I wrapped
one of the >75-column lines to fit in the commit guidelines.

0x50fc8@perf.data [0x260]: event: 84
.
. ... raw event: size 608 bytes
.  0000:  54 00 00 00 00 00 60 02 62 70 66 5f 70 72 6f 67  T.....`.bpf_prog
.  0010:  5f 31 65 30 61 32 65 33 36 36 65 35 36 66 31 61  _1e0a2e366e56f1a
.  0020:  32 5f 70 65 72 66 5f 73 61 6d 70 6c 65 5f 66 69  2_perf_sample_fi
.  0030:  6c 74 65 72 00 00 00 00 00 00 00 00 00 00 00 00  lter............
.  0040:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
[...]
.  0110:  74 65 73 74 5f 76 61 6c 75 65 00 00 00 00 00 00  test_value......
.  0120:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
[...]
.  0150:  34 32 00 00 00 00 00 00 00 00 00 00 00 00 00 00  42..............
.  0160:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
[...]

0 0x50fc8 [0x260]: PERF_RECORD_BPF_METADATA \
      prog bpf_prog_1e0a2e366e56f1a2_perf_sample_filter
  entry 0:           test_value = 42
: unhandled!

Signed-off-by: Blake Jones <blakejones@google.com>
Link: https://lore.kernel.org/r/20250612194939.162730-5-blakejones@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/builtin-inject.c
tools/perf/builtin-script.c
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/session.c
tools/perf/util/tool.c
tools/perf/util/tool.h

index 11e49cafa3af9d82b211d29b1c9123f12b1cddd2..b15eac0716f7d68c81aee36ead57c8d40bc765e4 100644 (file)
@@ -2530,6 +2530,7 @@ int cmd_inject(int argc, const char **argv)
        inject.tool.finished_init       = perf_event__repipe_op2_synth;
        inject.tool.compressed          = perf_event__repipe_op4_synth;
        inject.tool.auxtrace            = perf_event__repipe_auxtrace;
+       inject.tool.bpf_metadata        = perf_event__repipe_op2_synth;
        inject.tool.dont_split_sample_group = true;
        inject.session = __perf_session__new(&data, &inject.tool,
                                             /*trace_event_repipe=*/inject.output.is_pipe);
index 6c3bf74dd78c3967645cf4f8aaca2b4a7dccfaf5..4001e621b6cb76fed2443057ada8d1fa3f6a10e4 100644 (file)
@@ -38,6 +38,7 @@
 #include "print_insn.h"
 #include "archinsn.h"
 #include <linux/bitmap.h>
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/stringify.h>
 #include <linux/time64.h>
@@ -50,6 +51,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <signal.h>
+#include <stdio.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -2755,6 +2757,14 @@ process_bpf_events(const struct perf_tool *tool __maybe_unused,
                           sample->tid);
 }
 
+static int
+process_bpf_metadata_event(struct perf_session *session __maybe_unused,
+                          union perf_event *event)
+{
+       perf_event__fprintf(event, NULL, stdout);
+       return 0;
+}
+
 static int process_text_poke_events(const struct perf_tool *tool,
                                    union perf_event *event,
                                    struct perf_sample *sample,
@@ -2877,8 +2887,9 @@ static int __cmd_script(struct perf_script *script)
                script->tool.finished_round = process_finished_round_event;
        }
        if (script->show_bpf_events) {
-               script->tool.ksymbol = process_bpf_events;
-               script->tool.bpf     = process_bpf_events;
+               script->tool.ksymbol      = process_bpf_events;
+               script->tool.bpf          = process_bpf_events;
+               script->tool.bpf_metadata = process_bpf_metadata_event;
        }
        if (script->show_text_poke_events) {
                script->tool.ksymbol   = process_bpf_events;
index 7544a3104e21bb0481dd77e9aa509ea9ebe70fc8..14b0d368913758709413ba3d743b5d9030bf2148 100644 (file)
@@ -1,9 +1,12 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <perf/cpumap.h>
+#include <perf/event.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -78,6 +81,7 @@ static const char *perf_event__names[] = {
        [PERF_RECORD_COMPRESSED]                = "COMPRESSED",
        [PERF_RECORD_FINISHED_INIT]             = "FINISHED_INIT",
        [PERF_RECORD_COMPRESSED2]               = "COMPRESSED2",
+       [PERF_RECORD_BPF_METADATA]              = "BPF_METADATA",
 };
 
 const char *perf_event__name(unsigned int id)
@@ -505,6 +509,20 @@ size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp)
                       event->bpf.type, event->bpf.flags, event->bpf.id);
 }
 
+size_t perf_event__fprintf_bpf_metadata(union perf_event *event, FILE *fp)
+{
+       struct perf_record_bpf_metadata *metadata = &event->bpf_metadata;
+       size_t ret;
+
+       ret = fprintf(fp, " prog %s\n", metadata->prog_name);
+       for (__u32 i = 0; i < metadata->nr_entries; i++) {
+               ret += fprintf(fp, "  entry %d: %20s = %s\n", i,
+                              metadata->entries[i].key,
+                              metadata->entries[i].value);
+       }
+       return ret;
+}
+
 static int text_poke_printer(enum binary_printer_ops op, unsigned int val,
                             void *extra, FILE *fp)
 {
@@ -602,6 +620,9 @@ size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FIL
        case PERF_RECORD_AUX_OUTPUT_HW_ID:
                ret += perf_event__fprintf_aux_output_hw_id(event, fp);
                break;
+       case PERF_RECORD_BPF_METADATA:
+               ret += perf_event__fprintf_bpf_metadata(event, fp);
+               break;
        default:
                ret += fprintf(fp, "\n");
        }
index 664bf39567ce5dfa66151d0ad886a12b1cde49fb..67ad4a2014bca09af90d83d7fd0b245431d0ed7b 100644 (file)
@@ -370,6 +370,7 @@ size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_cgroup(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_bpf_metadata(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *machine,FILE *fp);
 size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FILE *fp);
 
index a320672c264e78ac221e279f57f553b04d940246..38075059086cd505e2e47bfbf4138558951279e9 100644 (file)
@@ -12,6 +12,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <perf/cpumap.h>
+#include <perf/event.h>
 
 #include "map_symbol.h"
 #include "branch.h"
@@ -1491,6 +1492,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
        case PERF_RECORD_FINISHED_INIT:
                err = tool->finished_init(session, event);
                break;
+       case PERF_RECORD_BPF_METADATA:
+               err = tool->bpf_metadata(session, event);
+               break;
        default:
                err = -EINVAL;
                break;
index 37bd8ac63b0117abd72a29c4ede74a4d644b02f7..204ec03071bc3e791f0332448455f713f6cc6874 100644 (file)
@@ -1,12 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "data.h"
 #include "debug.h"
+#include "event.h"
 #include "header.h"
 #include "session.h"
 #include "stat.h"
 #include "tool.h"
 #include "tsc.h"
+#include <linux/compiler.h>
 #include <sys/mman.h>
+#include <stddef.h>
 #include <unistd.h>
 
 #ifdef HAVE_ZSTD_SUPPORT
@@ -237,6 +240,16 @@ static int perf_session__process_compressed_event_stub(struct perf_session *sess
        return 0;
 }
 
+static int perf_event__process_bpf_metadata_stub(struct perf_session *perf_session __maybe_unused,
+                                                union perf_event *event)
+{
+       if (dump_trace)
+               perf_event__fprintf_bpf_metadata(event, stdout);
+
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
 void perf_tool__init(struct perf_tool *tool, bool ordered_events)
 {
        tool->ordered_events = ordered_events;
@@ -293,6 +306,7 @@ void perf_tool__init(struct perf_tool *tool, bool ordered_events)
        tool->compressed = perf_session__process_compressed_event_stub;
 #endif
        tool->finished_init = process_event_op2_stub;
+       tool->bpf_metadata = perf_event__process_bpf_metadata_stub;
 }
 
 bool perf_tool__compressed_is_stub(const struct perf_tool *tool)
index db1c7642b0d1564d0ebd6a19a92eb05b5e906a18..18b76ff0f26acddce8fa1303ec966d408055d78d 100644 (file)
@@ -77,7 +77,8 @@ struct perf_tool {
                        stat,
                        stat_round,
                        feature,
-                       finished_init;
+                       finished_init,
+                       bpf_metadata;
        event_op4       compressed;
        event_op3       auxtrace;
        bool            ordered_events;