[v5,perf,bpf,08/15] perf, bpf: save btf in a rbtree in perf_env
diff mbox series

Message ID 20190228050643.958685-9-songliubraving@fb.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series
  • perf annotation of BPF programs
Related show

Commit Message

Song Liu Feb. 28, 2019, 5:06 a.m. UTC
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>
---
 tools/perf/util/bpf-event.c | 24 ++++++++++++++
 tools/perf/util/bpf-event.h |  7 ++++
 tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       |  4 +++
 4 files changed, 100 insertions(+)

Comments

Jiri Olsa March 4, 2019, 1:52 p.m. UTC | #1
On Wed, Feb 27, 2019 at 09:06:36PM -0800, Song Liu wrote:
> 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>
> ---
>  tools/perf/util/bpf-event.c | 24 ++++++++++++++
>  tools/perf/util/bpf-event.h |  7 ++++
>  tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
>  tools/perf/util/env.h       |  4 +++
>  4 files changed, 100 insertions(+)
> 
> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> index ce81b2c43a51..370b830f2433 100644
> --- a/tools/perf/util/bpf-event.c
> +++ b/tools/perf/util/bpf-event.c
> @@ -34,6 +34,29 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
>  	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);

why don't we store just struct btf itself?

thanks,
jirka
Jiri Olsa March 4, 2019, 1:53 p.m. UTC | #2
On Wed, Feb 27, 2019 at 09:06:36PM -0800, Song Liu wrote:
> 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>
> ---
>  tools/perf/util/bpf-event.c | 24 ++++++++++++++
>  tools/perf/util/bpf-event.h |  7 ++++
>  tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
>  tools/perf/util/env.h       |  4 +++
>  4 files changed, 100 insertions(+)
> 
> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> index ce81b2c43a51..370b830f2433 100644
> --- a/tools/perf/util/bpf-event.c
> +++ b/tools/perf/util/bpf-event.c
> @@ -34,6 +34,29 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
>  	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));
> +

extra new line

> +	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;
> +}

SNIP
Song Liu March 4, 2019, 7:43 p.m. UTC | #3
> On Mar 4, 2019, at 5:52 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Wed, Feb 27, 2019 at 09:06:36PM -0800, Song Liu wrote:
>> 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>
>> ---
>> tools/perf/util/bpf-event.c | 24 ++++++++++++++
>> tools/perf/util/bpf-event.h |  7 ++++
>> tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
>> tools/perf/util/env.h       |  4 +++
>> 4 files changed, 100 insertions(+)
>> 
>> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
>> index ce81b2c43a51..370b830f2433 100644
>> --- a/tools/perf/util/bpf-event.c
>> +++ b/tools/perf/util/bpf-event.c
>> @@ -34,6 +34,29 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
>> 	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);
> 
> why don't we store just struct btf itself?
> 
> thanks,
> jirka

In current libbpf design, definition of "struct btf" is private 
to tools/lib/bpf/btf.c. So we cannot copy the struct itself. 

Thanks,
Song
Jiri Olsa March 4, 2019, 8:31 p.m. UTC | #4
On Mon, Mar 04, 2019 at 07:43:50PM +0000, Song Liu wrote:
> 
> 
> > On Mar 4, 2019, at 5:52 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> > 
> > On Wed, Feb 27, 2019 at 09:06:36PM -0800, Song Liu wrote:
> >> 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>
> >> ---
> >> tools/perf/util/bpf-event.c | 24 ++++++++++++++
> >> tools/perf/util/bpf-event.h |  7 ++++
> >> tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
> >> tools/perf/util/env.h       |  4 +++
> >> 4 files changed, 100 insertions(+)
> >> 
> >> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> >> index ce81b2c43a51..370b830f2433 100644
> >> --- a/tools/perf/util/bpf-event.c
> >> +++ b/tools/perf/util/bpf-event.c
> >> @@ -34,6 +34,29 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
> >> 	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);
> > 
> > why don't we store just struct btf itself?
> > 
> > thanks,
> > jirka
> 
> In current libbpf design, definition of "struct btf" is private 
> to tools/lib/bpf/btf.c. So we cannot copy the struct itself. 

ok

jirka

Patch
diff mbox series

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index ce81b2c43a51..370b830f2433 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -34,6 +34,29 @@  int machine__process_bpf_event(struct machine *machine __maybe_unused,
 	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
  * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
@@ -113,6 +136,7 @@  static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 			goto out;
 		}
 		has_btf = true;
+		perf_env__fetch_btf(env, info->btf_id, btf);
 	}
 
 	/* Synthesize PERF_RECORD_KSYMBOL */
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index fad932f7404f..b9ec394dc7c7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -16,6 +16,13 @@  struct bpf_prog_info_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
 int machine__process_bpf_event(struct machine *machine, union perf_event *event,
 			       struct perf_sample *sample);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index cdda46f2633f..9e4ee7b0a3d1 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -63,6 +63,57 @@  struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
 	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);
+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 */
 static void perf_env__purge_bpf(struct perf_env *env)
 {
@@ -82,6 +133,19 @@  static void perf_env__purge_bpf(struct perf_env *env)
 		rb_erase_init(&node->rb_node, root);
 		free(node);
 	}
+
+	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_init(&node->rb_node, root);
+		free(node);
+	}
+
 	up_write(&env->bpf_progs.lock);
 }
 
@@ -119,6 +183,7 @@  void perf_env__exit(struct perf_env *env)
 void perf_env__init(struct perf_env *env)
 {
 	env->bpf_progs.infos = RB_ROOT;
+	env->bpf_progs.btfs = RB_ROOT;
 	init_rwsem(&env->bpf_progs.lock);
 }
 
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index e034e5b438e3..c3e48504e834 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -74,10 +74,12 @@  struct perf_env {
 	struct {
 		struct rw_semaphore	lock;
 		struct rb_root		infos;
+		struct rb_root		btfs;
 	} bpf_progs;
 };
 
 struct bpf_prog_info_node;
+struct btf_node;
 
 extern struct perf_env perf_env;
 
@@ -98,4 +100,6 @@  void perf_env__insert_bpf_prog_info(struct perf_env *env,
 				    struct bpf_prog_info_node *info_node);
 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
 							__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 */