]> www.infradead.org Git - users/jedix/linux-maple.git/commit
perf trace: Support collecting 'union's with the BPF augmenter
authorArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 10 Sep 2024 13:17:21 +0000 (10:17 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 10 Sep 2024 20:31:51 +0000 (17:31 -0300)
commitf3f16112c65f5923f41d9d7222fe7e4f34bf73ad
tree798c7e2b0b5fe1456f4129491009241a951a4500
parent3278024540e882b21e915afb507522e8e01ca160
perf trace: Support collecting 'union's with the BPF augmenter

And reuse the BTF based struct pretty printer, with that we can offer
initial support for the 'bpf' syscall's second argument, a 'union
bpf_attr' pointer.

But this is not that satisfactory as the libbpf btf dumper will pretty
print _all_ the union, we need to have a way to say that the first arg
selects the type for the union member to be pretty printed, something
like what pahole does translating the PERF_RECORD_ selector into a name,
and using that name to find a matching struct.

In the case of 'union bpf_attr' it would map PROG_LOAD to one of the
union members, but unfortunately there is no such mapping:

  root@number:~# pahole bpf_attr
  union bpf_attr {
   struct {
   __u32              map_type;           /*     0     4 */
   __u32              key_size;           /*     4     4 */
   __u32              value_size;         /*     8     4 */
   __u32              max_entries;        /*    12     4 */
   __u32              map_flags;          /*    16     4 */
   __u32              inner_map_fd;       /*    20     4 */
   __u32              numa_node;          /*    24     4 */
   char               map_name[16];       /*    28    16 */
   __u32              map_ifindex;        /*    44     4 */
   __u32              btf_fd;             /*    48     4 */
   __u32              btf_key_type_id;    /*    52     4 */
   __u32              btf_value_type_id;  /*    56     4 */
   __u32              btf_vmlinux_value_type_id; /*    60     4 */
   /* --- cacheline 1 boundary (64 bytes) --- */
   __u64              map_extra;          /*    64     8 */
   __s32              value_type_btf_obj_fd; /*    72     4 */
   __s32              map_token_fd;       /*    76     4 */
   };                                             /*     0    80 */
   struct {
   __u32              map_fd;             /*     0     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64              key;                /*     8     8 */
   union {
   __u64      value;              /*    16     8 */
   __u64      next_key;           /*    16     8 */
   };                                     /*    16     8 */
   __u64              flags;              /*    24     8 */
   };                                             /*     0    32 */
   struct {
   __u64              in_batch;           /*     0     8 */
   __u64              out_batch;          /*     8     8 */
   __u64              keys;               /*    16     8 */
   __u64              values;             /*    24     8 */
   __u32              count;              /*    32     4 */
   __u32              map_fd;             /*    36     4 */
   __u64              elem_flags;         /*    40     8 */
   __u64              flags;              /*    48     8 */
   } batch;                                       /*     0    56 */
   struct {
   __u32              prog_type;          /*     0     4 */
   __u32              insn_cnt;           /*     4     4 */
   __u64              insns;              /*     8     8 */
   __u64              license;            /*    16     8 */
   __u32              log_level;          /*    24     4 */
   __u32              log_size;           /*    28     4 */
   __u64              log_buf;            /*    32     8 */
   __u32              kern_version;       /*    40     4 */
   __u32              prog_flags;         /*    44     4 */
   char               prog_name[16];      /*    48    16 */
   /* --- cacheline 1 boundary (64 bytes) --- */
   __u32              prog_ifindex;       /*    64     4 */
   __u32              expected_attach_type; /*    68     4 */
   __u32              prog_btf_fd;        /*    72     4 */
   __u32              func_info_rec_size; /*    76     4 */
   __u64              func_info;          /*    80     8 */
   __u32              func_info_cnt;      /*    88     4 */
   __u32              line_info_rec_size; /*    92     4 */
   __u64              line_info;          /*    96     8 */
   __u32              line_info_cnt;      /*   104     4 */
   __u32              attach_btf_id;      /*   108     4 */
   union {
   __u32      attach_prog_fd;     /*   112     4 */
   __u32      attach_btf_obj_fd;  /*   112     4 */
   };                                     /*   112     4 */
   __u32              core_relo_cnt;      /*   116     4 */
   __u64              fd_array;           /*   120     8 */
   /* --- cacheline 2 boundary (128 bytes) --- */
   __u64              core_relos;         /*   128     8 */
   __u32              core_relo_rec_size; /*   136     4 */
   __u32              log_true_size;      /*   140     4 */
   __s32              prog_token_fd;      /*   144     4 */
   };                                             /*     0   152 */
   struct {
   __u64              pathname;           /*     0     8 */
   __u32              bpf_fd;             /*     8     4 */
   __u32              file_flags;         /*    12     4 */
   __s32              path_fd;            /*    16     4 */
   };                                             /*     0    24 */
   struct {
   union {
   __u32      target_fd;          /*     0     4 */
   __u32      target_ifindex;     /*     0     4 */
   };                                     /*     0     4 */
   __u32              attach_bpf_fd;      /*     4     4 */
   __u32              attach_type;        /*     8     4 */
   __u32              attach_flags;       /*    12     4 */
   __u32              replace_bpf_fd;     /*    16     4 */
   union {
   __u32      relative_fd;        /*    20     4 */
   __u32      relative_id;        /*    20     4 */
   };                                     /*    20     4 */
   __u64              expected_revision;  /*    24     8 */
   };                                             /*     0    32 */
   struct {
   __u32              prog_fd;            /*     0     4 */
   __u32              retval;             /*     4     4 */
   __u32              data_size_in;       /*     8     4 */
   __u32              data_size_out;      /*    12     4 */
   __u64              data_in;            /*    16     8 */
   __u64              data_out;           /*    24     8 */
   __u32              repeat;             /*    32     4 */
   __u32              duration;           /*    36     4 */
   __u32              ctx_size_in;        /*    40     4 */
   __u32              ctx_size_out;       /*    44     4 */
   __u64              ctx_in;             /*    48     8 */
   __u64              ctx_out;            /*    56     8 */
   /* --- cacheline 1 boundary (64 bytes) --- */
   __u32              flags;              /*    64     4 */
   __u32              cpu;                /*    68     4 */
   __u32              batch_size;         /*    72     4 */
   } test;                                        /*     0    80 */
   struct {
   union {
   __u32      start_id;           /*     0     4 */
   __u32      prog_id;            /*     0     4 */
   __u32      map_id;             /*     0     4 */
   __u32      btf_id;             /*     0     4 */
   __u32      link_id;            /*     0     4 */
   };                                     /*     0     4 */
   __u32              next_id;            /*     4     4 */
   __u32              open_flags;         /*     8     4 */
   };                                             /*     0    12 */
   struct {
   __u32              bpf_fd;             /*     0     4 */
   __u32              info_len;           /*     4     4 */
   __u64              info;               /*     8     8 */
   } info;                                        /*     0    16 */
   struct {
   union {
   __u32      target_fd;          /*     0     4 */
   __u32      target_ifindex;     /*     0     4 */
   };                                     /*     0     4 */
   __u32              attach_type;        /*     4     4 */
   __u32              query_flags;        /*     8     4 */
   __u32              attach_flags;       /*    12     4 */
   __u64              prog_ids;           /*    16     8 */
   union {
   __u32      prog_cnt;           /*    24     4 */
   __u32      count;              /*    24     4 */
   };                                     /*    24     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64              prog_attach_flags;  /*    32     8 */
   __u64              link_ids;           /*    40     8 */
   __u64              link_attach_flags;  /*    48     8 */
   __u64              revision;           /*    56     8 */
   } query;                                       /*     0    64 */
   struct {
   __u64              name;               /*     0     8 */
   __u32              prog_fd;            /*     8     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64              cookie;             /*    16     8 */
   } raw_tracepoint;                              /*     0    24 */
   struct {
   __u64              btf;                /*     0     8 */
   __u64              btf_log_buf;        /*     8     8 */
   __u32              btf_size;           /*    16     4 */
   __u32              btf_log_size;       /*    20     4 */
   __u32              btf_log_level;      /*    24     4 */
   __u32              btf_log_true_size;  /*    28     4 */
   __u32              btf_flags;          /*    32     4 */
   __s32              btf_token_fd;       /*    36     4 */
   };                                             /*     0    40 */
   struct {
   __u32              pid;                /*     0     4 */
   __u32              fd;                 /*     4     4 */
   __u32              flags;              /*     8     4 */
   __u32              buf_len;            /*    12     4 */
   __u64              buf;                /*    16     8 */
   __u32              prog_id;            /*    24     4 */
   __u32              fd_type;            /*    28     4 */
   __u64              probe_offset;       /*    32     8 */
   __u64              probe_addr;         /*    40     8 */
   } task_fd_query;                               /*     0    48 */
   struct {
   union {
   __u32      prog_fd;            /*     0     4 */
   __u32      map_fd;             /*     0     4 */
   };                                     /*     0     4 */
   union {
   __u32      target_fd;          /*     4     4 */
   __u32      target_ifindex;     /*     4     4 */
   };                                     /*     4     4 */
   __u32              attach_type;        /*     8     4 */
   __u32              flags;              /*    12     4 */
   union {
   __u32      target_btf_id;      /*    16     4 */
   struct {
   __u64 iter_info;       /*    16     8 */
   __u32 iter_info_len;   /*    24     4 */
   };                             /*    16    16 */
   struct {
   __u64 bpf_cookie;      /*    16     8 */
   } perf_event;                  /*    16     8 */
   struct {
   __u32 flags;           /*    16     4 */
   __u32 cnt;             /*    20     4 */
   __u64 syms;            /*    24     8 */
   __u64 addrs;           /*    32     8 */
   __u64 cookies;         /*    40     8 */
   } kprobe_multi;                /*    16    32 */
   struct {
   __u32 target_btf_id;   /*    16     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64 cookie;          /*    24     8 */
   } tracing;                     /*    16    16 */
   struct {
   __u32 pf;              /*    16     4 */
   __u32 hooknum;         /*    20     4 */
   __s32 priority;        /*    24     4 */
   __u32 flags;           /*    28     4 */
   } netfilter;                   /*    16    16 */
   struct {
   union {
   __u32  relative_fd; /*    16     4 */
   __u32  relative_id; /*    16     4 */
   };                     /*    16     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64 expected_revision; /*    24     8 */
   } tcx;                         /*    16    16 */
   struct {
   __u64 path;            /*    16     8 */
   __u64 offsets;         /*    24     8 */
   __u64 ref_ctr_offsets; /*    32     8 */
   __u64 cookies;         /*    40     8 */
   __u32 cnt;             /*    48     4 */
   __u32 flags;           /*    52     4 */
   __u32 pid;             /*    56     4 */
   } uprobe_multi;                /*    16    48 */
   struct {
   union {
   __u32  relative_fd; /*    16     4 */
   __u32  relative_id; /*    16     4 */
   };                     /*    16     4 */

   /* XXX 4 bytes hole, try to pack */

   __u64 expected_revision; /*    24     8 */
   } netkit;                      /*    16    16 */
   };                                     /*    16    48 */
   } link_create;                                 /*     0    64 */
   struct {
   __u32              link_fd;            /*     0     4 */
   union {
   __u32      new_prog_fd;        /*     4     4 */
   __u32      new_map_fd;         /*     4     4 */
   };                                     /*     4     4 */
   __u32              flags;              /*     8     4 */
   union {
   __u32      old_prog_fd;        /*    12     4 */
   __u32      old_map_fd;         /*    12     4 */
   };                                     /*    12     4 */
   } link_update;                                 /*     0    16 */
   struct {
   __u32              link_fd;            /*     0     4 */
   } link_detach;                                 /*     0     4 */
   struct {
   __u32              type;               /*     0     4 */
   } enable_stats;                                /*     0     4 */
   struct {
   __u32              link_fd;            /*     0     4 */
   __u32              flags;              /*     4     4 */
   } iter_create;                                 /*     0     8 */
   struct {
   __u32              prog_fd;            /*     0     4 */
   __u32              map_fd;             /*     4     4 */
   __u32              flags;              /*     8     4 */
   } prog_bind_map;                               /*     0    12 */
   struct {
   __u32              flags;              /*     0     4 */
   __u32              bpffs_fd;           /*     4     4 */
   } token_create;                                /*     0     8 */
  };

  root@number:~#

So this is one case where BTF gets us only that far, not getting all
the way to automate the pretty printing of unions designed like 'union
bpf_attr', we will need a custom pretty printer for this union, as using
the libbpf union BTF dumper is way too verbose:

  root@number:~# perf trace --max-events 1 -e bpf bpftool map
       0.000 ( 0.054 ms): bpftool/3409073 bpf(cmd: PROG_LOAD, uattr: (union bpf_attr){(struct){.map_type = (__u32)1,.key_size = (__u32)2,.value_size = (__u32)2755142048,.max_entries = (__u32)32764,.map_flags = (__u32)150263906,.inner_map_fd = (__u32)21920,},(struct){.map_fd = (__u32)1,.key = (__u64)140723063628192,(union){.value = (__u64)94145833392226,.next_key = (__u64)94145833392226,},},.batch = (struct){.in_batch = (__u64)8589934593,.out_batch = (__u64)140723063628192,.keys = (__u64)94145833392226,},(struct){.prog_type = (__u32)1,.insn_cnt = (__u32)2,.insns = (__u64)140723063628192,.license = (__u64)94145833392226,},(struct){.pathname = (__u64)8589934593,.bpf_fd = (__u32)2755142048,.file_flags = (__u32)32764,.path_fd = (__s32)150263906,},(struct){(union){.target_fd = (__u32)1,.target_ifindex = (__u32)1,},.attach_bpf_fd = (__u32)2,.attach_type = (__u32)2755142048,.attach_flags = (__u32)32764,.replace_bpf_fd = (__u32)150263906,(union){.relative_fd = (__u32)21920,.relative_id = (__u32)21920,},},.test = (struct){.prog_fd = (__u32)1,.retval = (__u32)2,.data_size_in = (__u32)2755142048,.data_size_out = (__u32)32764,.data_in = (__u64)94145833392226,},(struct){(union){.start_id = (__u32)1,.prog_id = (__u32)1,.map_id = (__u32)1,.btf_id = (__u32)1,.link_id = (__u32)1,},.next_id = (__u32)2,.open_flags = (__u32)2755142048,},.info = (struct){.bpf_fd = (__u32)1,.info_len = (__u32)2,.info = (__u64)140723063628192,},.query = (struct){(union){.target_fd = (__u32)1,.target_ifindex = (__u32)1,},.attach_type = (__u32)2,.query_flags = (__u32)2755142048,.attach_flags = (__u32)32764,.prog_ids = (__u64)94145833392226,},.raw_tracepoint = (struct){.name = (__u64)8589934593,.prog_fd = (__u32)2755142048,.cookie = (__u64)94145833392226,},(struct){.btf = (__u64)8589934593,.btf_log_buf = (__u64)140723063628192,.btf_size = (__u32)150263906,.btf_log_size = (__u32)21920,},.task_fd_query = (struct){.pid = (__u32)1,.fd = (__u32)2,.flags = (__u32)2755142048,.buf_len = (__u32)32764,.buf = (__u64)94145833392226,},.link_create = (struct){(union){.prog_fd = (__u32)1,.map_fd = (__u32)1,},(u) = 3
  root@number:~# 2: prog_array  name hid_jmp_table  flags 0x0
   key 4B  value 4B  max_entries 1024  memlock 8440B
   owner_prog_type tracing  owner jited
  13: hash_of_maps  name cgroup_hash  flags 0x0
   key 8B  value 4B  max_entries 2048  memlock 167584B
   pids systemd(1)
  960: array  name libbpf_global  flags 0x0
   key 4B  value 32B  max_entries 1  memlock 280B
  961: array  name pid_iter.rodata  flags 0x480
   key 4B  value 4B  max_entries 1  memlock 8192B
   btf_id 1846  frozen
   pids bpftool(3409073)
  962: array  name libbpf_det_bind  flags 0x0
   key 4B  value 32B  max_entries 1  memlock 280B

  root@number:~#

For simpler unions this may be better than not seeing any payload, so
keep it there.

Acked-by: Howard Chu <howardchu95@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/lkml/ZuBLat8cbadILNLA@x1
[ Removed needless parenteses in the if block leading to the trace__btf_scnprintf() call, as per Howard's review comments ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-trace.c