forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									606f972b13
								
							
						
					
					
						commit
						3792cb2ff4
					
				
					 4 changed files with 102 additions and 0 deletions
				
			
		|  | @ -34,6 +34,28 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int perf_env__fetch_btf(struct perf_env *env, | ||||||
|  | 			       u32 btf_id, | ||||||
|  | 			       struct btf *btf) | ||||||
|  | { | ||||||
|  | 	struct btf_node *node; | ||||||
|  | 	u32 data_size; | ||||||
|  | 	const void *data; | ||||||
|  | 
 | ||||||
|  | 	data = btf__get_raw_data(btf, &data_size); | ||||||
|  | 
 | ||||||
|  | 	node = malloc(data_size + sizeof(struct btf_node)); | ||||||
|  | 	if (!node) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	node->id = btf_id; | ||||||
|  | 	node->data_size = data_size; | ||||||
|  | 	memcpy(node->data, data, data_size); | ||||||
|  | 
 | ||||||
|  | 	perf_env__insert_btf(env, node); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf |  * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf | ||||||
|  * program. One PERF_RECORD_BPF_EVENT is generated for the program. And |  * program. One PERF_RECORD_BPF_EVENT is generated for the program. And | ||||||
|  | @ -113,6 +135,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 		has_btf = true; | 		has_btf = true; | ||||||
|  | 		perf_env__fetch_btf(env, info->btf_id, btf); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Synthesize PERF_RECORD_KSYMBOL */ | 	/* Synthesize PERF_RECORD_KSYMBOL */ | ||||||
|  |  | ||||||
|  | @ -16,6 +16,13 @@ struct bpf_prog_info_node { | ||||||
| 	struct rb_node			rb_node; | 	struct rb_node			rb_node; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct btf_node { | ||||||
|  | 	struct rb_node	rb_node; | ||||||
|  | 	u32		id; | ||||||
|  | 	u32		data_size; | ||||||
|  | 	char		data[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #ifdef HAVE_LIBBPF_SUPPORT | #ifdef HAVE_LIBBPF_SUPPORT | ||||||
| int machine__process_bpf_event(struct machine *machine, union perf_event *event, | int machine__process_bpf_event(struct machine *machine, union perf_event *event, | ||||||
| 			       struct perf_sample *sample); | 			       struct perf_sample *sample); | ||||||
|  |  | ||||||
|  | @ -64,6 +64,58 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, | ||||||
| 	return node; | 	return node; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) | ||||||
|  | { | ||||||
|  | 	struct rb_node *parent = NULL; | ||||||
|  | 	__u32 btf_id = btf_node->id; | ||||||
|  | 	struct btf_node *node; | ||||||
|  | 	struct rb_node **p; | ||||||
|  | 
 | ||||||
|  | 	down_write(&env->bpf_progs.lock); | ||||||
|  | 	p = &env->bpf_progs.btfs.rb_node; | ||||||
|  | 
 | ||||||
|  | 	while (*p != NULL) { | ||||||
|  | 		parent = *p; | ||||||
|  | 		node = rb_entry(parent, struct btf_node, rb_node); | ||||||
|  | 		if (btf_id < node->id) { | ||||||
|  | 			p = &(*p)->rb_left; | ||||||
|  | 		} else if (btf_id > node->id) { | ||||||
|  | 			p = &(*p)->rb_right; | ||||||
|  | 		} else { | ||||||
|  | 			pr_debug("duplicated btf %u\n", btf_id); | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rb_link_node(&btf_node->rb_node, parent, p); | ||||||
|  | 	rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs); | ||||||
|  | 	env->bpf_progs.btfs_cnt++; | ||||||
|  | out: | ||||||
|  | 	up_write(&env->bpf_progs.lock); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) | ||||||
|  | { | ||||||
|  | 	struct btf_node *node = NULL; | ||||||
|  | 	struct rb_node *n; | ||||||
|  | 
 | ||||||
|  | 	down_read(&env->bpf_progs.lock); | ||||||
|  | 	n = env->bpf_progs.btfs.rb_node; | ||||||
|  | 
 | ||||||
|  | 	while (n) { | ||||||
|  | 		node = rb_entry(n, struct btf_node, rb_node); | ||||||
|  | 		if (btf_id < node->id) | ||||||
|  | 			n = n->rb_left; | ||||||
|  | 		else if (btf_id > node->id) | ||||||
|  | 			n = n->rb_right; | ||||||
|  | 		else | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	up_read(&env->bpf_progs.lock); | ||||||
|  | 	return node; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* purge data in bpf_progs.infos tree */ | /* purge data in bpf_progs.infos tree */ | ||||||
| static void perf_env__purge_bpf(struct perf_env *env) | static void perf_env__purge_bpf(struct perf_env *env) | ||||||
| { | { | ||||||
|  | @ -86,6 +138,20 @@ static void perf_env__purge_bpf(struct perf_env *env) | ||||||
| 
 | 
 | ||||||
| 	env->bpf_progs.infos_cnt = 0; | 	env->bpf_progs.infos_cnt = 0; | ||||||
| 
 | 
 | ||||||
|  | 	root = &env->bpf_progs.btfs; | ||||||
|  | 	next = rb_first(root); | ||||||
|  | 
 | ||||||
|  | 	while (next) { | ||||||
|  | 		struct btf_node *node; | ||||||
|  | 
 | ||||||
|  | 		node = rb_entry(next, struct btf_node, rb_node); | ||||||
|  | 		next = rb_next(&node->rb_node); | ||||||
|  | 		rb_erase(&node->rb_node, root); | ||||||
|  | 		free(node); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	env->bpf_progs.btfs_cnt = 0; | ||||||
|  | 
 | ||||||
| 	up_write(&env->bpf_progs.lock); | 	up_write(&env->bpf_progs.lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -123,6 +189,7 @@ void perf_env__exit(struct perf_env *env) | ||||||
| void perf_env__init(struct perf_env *env) | void perf_env__init(struct perf_env *env) | ||||||
| { | { | ||||||
| 	env->bpf_progs.infos = RB_ROOT; | 	env->bpf_progs.infos = RB_ROOT; | ||||||
|  | 	env->bpf_progs.btfs = RB_ROOT; | ||||||
| 	init_rwsem(&env->bpf_progs.lock); | 	init_rwsem(&env->bpf_progs.lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -75,10 +75,13 @@ struct perf_env { | ||||||
| 		struct rw_semaphore	lock; | 		struct rw_semaphore	lock; | ||||||
| 		struct rb_root		infos; | 		struct rb_root		infos; | ||||||
| 		u32			infos_cnt; | 		u32			infos_cnt; | ||||||
|  | 		struct rb_root		btfs; | ||||||
|  | 		u32			btfs_cnt; | ||||||
| 	} bpf_progs; | 	} bpf_progs; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct bpf_prog_info_node; | struct bpf_prog_info_node; | ||||||
|  | struct btf_node; | ||||||
| 
 | 
 | ||||||
| extern struct perf_env perf_env; | extern struct perf_env perf_env; | ||||||
| 
 | 
 | ||||||
|  | @ -99,4 +102,6 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env, | ||||||
| 				    struct bpf_prog_info_node *info_node); | 				    struct bpf_prog_info_node *info_node); | ||||||
| struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, | struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env, | ||||||
| 							__u32 prog_id); | 							__u32 prog_id); | ||||||
|  | void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node); | ||||||
|  | struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id); | ||||||
| #endif /* __PERF_ENV_H */ | #endif /* __PERF_ENV_H */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Song Liu
						Song Liu