Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf bpf: Save BTF in a rbtree in perf_env

BTF contains information necessary to annotate BPF programs. This patch
saves BTF for BPF programs loaded in the system.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-9-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Song Liu and committed by
Arnaldo Carvalho de Melo
3792cb2f 606f972b

+102
+23
tools/perf/util/bpf-event.c
··· 34 34 return 0; 35 35 } 36 36 37 + static int perf_env__fetch_btf(struct perf_env *env, 38 + u32 btf_id, 39 + struct btf *btf) 40 + { 41 + struct btf_node *node; 42 + u32 data_size; 43 + const void *data; 44 + 45 + data = btf__get_raw_data(btf, &data_size); 46 + 47 + node = malloc(data_size + sizeof(struct btf_node)); 48 + if (!node) 49 + return -1; 50 + 51 + node->id = btf_id; 52 + node->data_size = data_size; 53 + memcpy(node->data, data, data_size); 54 + 55 + perf_env__insert_btf(env, node); 56 + return 0; 57 + } 58 + 37 59 /* 38 60 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf 39 61 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And ··· 135 113 goto out; 136 114 } 137 115 has_btf = true; 116 + perf_env__fetch_btf(env, info->btf_id, btf); 138 117 } 139 118 140 119 /* Synthesize PERF_RECORD_KSYMBOL */
+7
tools/perf/util/bpf-event.h
··· 16 16 struct rb_node rb_node; 17 17 }; 18 18 19 + struct btf_node { 20 + struct rb_node rb_node; 21 + u32 id; 22 + u32 data_size; 23 + char data[]; 24 + }; 25 + 19 26 #ifdef HAVE_LIBBPF_SUPPORT 20 27 int machine__process_bpf_event(struct machine *machine, union perf_event *event, 21 28 struct perf_sample *sample);
+67
tools/perf/util/env.c
··· 64 64 return node; 65 65 } 66 66 67 + void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) 68 + { 69 + struct rb_node *parent = NULL; 70 + __u32 btf_id = btf_node->id; 71 + struct btf_node *node; 72 + struct rb_node **p; 73 + 74 + down_write(&env->bpf_progs.lock); 75 + p = &env->bpf_progs.btfs.rb_node; 76 + 77 + while (*p != NULL) { 78 + parent = *p; 79 + node = rb_entry(parent, struct btf_node, rb_node); 80 + if (btf_id < node->id) { 81 + p = &(*p)->rb_left; 82 + } else if (btf_id > node->id) { 83 + p = &(*p)->rb_right; 84 + } else { 85 + pr_debug("duplicated btf %u\n", btf_id); 86 + goto out; 87 + } 88 + } 89 + 90 + rb_link_node(&btf_node->rb_node, parent, p); 91 + rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs); 92 + env->bpf_progs.btfs_cnt++; 93 + out: 94 + up_write(&env->bpf_progs.lock); 95 + } 96 + 97 + struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) 98 + { 99 + struct btf_node *node = NULL; 100 + struct rb_node *n; 101 + 102 + down_read(&env->bpf_progs.lock); 103 + n = env->bpf_progs.btfs.rb_node; 104 + 105 + while (n) { 106 + node = rb_entry(n, struct btf_node, rb_node); 107 + if (btf_id < node->id) 108 + n = n->rb_left; 109 + else if (btf_id > node->id) 110 + n = n->rb_right; 111 + else 112 + break; 113 + } 114 + 115 + up_read(&env->bpf_progs.lock); 116 + return node; 117 + } 118 + 67 119 /* purge data in bpf_progs.infos tree */ 68 120 static void perf_env__purge_bpf(struct perf_env *env) 69 121 { ··· 137 85 } 138 86 139 87 env->bpf_progs.infos_cnt = 0; 88 + 89 + root = &env->bpf_progs.btfs; 90 + next = rb_first(root); 91 + 92 + while (next) { 93 + struct btf_node *node; 94 + 95 + node = rb_entry(next, struct btf_node, rb_node); 96 + next = rb_next(&node->rb_node); 97 + rb_erase(&node->rb_node, root); 98 + free(node); 99 + } 100 + 101 + env->bpf_progs.btfs_cnt = 0; 140 102 141 103 up_write(&env->bpf_progs.lock); 142 104 } ··· 189 123 void perf_env__init(struct perf_env *env) 190 124 { 191 125 env->bpf_progs.infos = RB_ROOT; 126 + env->bpf_progs.btfs = RB_ROOT; 192 127 init_rwsem(&env->bpf_progs.lock); 193 128 } 194 129
+5
tools/perf/util/env.h
··· 75 75 struct rw_semaphore lock; 76 76 struct rb_root infos; 77 77 u32 infos_cnt; 78 + struct rb_root btfs; 79 + u32 btfs_cnt; 78 80 } bpf_progs; 79 81 }; 80 82 81 83 struct bpf_prog_info_node; 84 + struct btf_node; 82 85 83 86 extern struct perf_env perf_env; 84 87 ··· 102 99 struct bpf_prog_info_node *info_node); 103 100 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, 104 101 __u32 prog_id); 102 + void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node); 103 + struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id); 105 104 #endif /* __PERF_ENV_H */