Skip to content

Commit e4378f0

Browse files
liu-song-6acmel
authored andcommitted
perf bpf: Save bpf_prog_info in a rbtree in perf_env
bpf_prog_info contains information necessary to annotate bpf programs. This patch saves bpf_prog_info for bpf programs loaded in the system. Some big picture of the next few patches: To fully annotate BPF programs with source code mapping, 4 different informations are needed: 1) PERF_RECORD_KSYMBOL 2) PERF_RECORD_BPF_EVENT 3) bpf_prog_info 4) btf Before this set, 1) and 2) in the list are already saved to perf.data file. For BPF programs that are already loaded before perf run, 1) and 2) are synthesized by perf_event__synthesize_bpf_events(). For short living BPF programs, 1) and 2) are generated by kernel. This set handles 3) and 4) from the list. Again, it is necessary to handle existing BPF program and short living program separately. This patch handles 3) for exising BPF programs while synthesizing 1) and 2) in perf_event__synthesize_bpf_events(). These data are stored in perf_env. The next patch saves these data from perf_env to perf.data as headers. Similarly, the two patches after the next saves 4) of existing BPF programs to perf_env and perf.data. Another patch later will handle 3) and 4) for short living BPF programs by monitoring 1) and 2) in a dedicate thread. Signed-off-by: Song Liu <[email protected]> Reviewed-by: Jiri Olsa <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Daniel Borkmann <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stanislav Fomichev <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] [ set env->bpf_progs.infos_cnt to zero in perf_env__purge_bpf() as noted by jolsa ] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent e541695 commit e4378f0

File tree

6 files changed

+144
-2
lines changed

6 files changed

+144
-2
lines changed

tools/perf/perf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
298298
use_pager = 1;
299299
commit_pager_choice();
300300

301+
perf_env__init(&perf_env);
301302
perf_env__set_cmdline(&perf_env, argc, argv);
302303
status = p->fn(argc, argv);
303304
perf_config__exit();

tools/perf/util/bpf-event.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "debug.h"
1111
#include "symbol.h"
1212
#include "machine.h"
13+
#include "env.h"
1314
#include "session.h"
1415

1516
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
@@ -54,17 +55,28 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
5455
struct bpf_event *bpf_event = &event->bpf_event;
5556
struct bpf_prog_info_linear *info_linear;
5657
struct perf_tool *tool = session->tool;
58+
struct bpf_prog_info_node *info_node;
5759
struct bpf_prog_info *info;
5860
struct btf *btf = NULL;
5961
bool has_btf = false;
62+
struct perf_env *env;
6063
u32 sub_prog_cnt, i;
6164
int err = 0;
6265
u64 arrays;
6366

67+
/*
68+
* for perf-record and perf-report use header.env;
69+
* otherwise, use global perf_env.
70+
*/
71+
env = session->data ? &session->header.env : &perf_env;
72+
6473
arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
6574
arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
6675
arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
6776
arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
77+
arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
78+
arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
79+
arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
6880

6981
info_linear = bpf_program__get_prog_info_linear(fd, arrays);
7082
if (IS_ERR_OR_NULL(info_linear)) {
@@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
153165
machine, process);
154166
}
155167

156-
/* Synthesize PERF_RECORD_BPF_EVENT */
157168
if (!opts->no_bpf_event) {
169+
/* Synthesize PERF_RECORD_BPF_EVENT */
158170
*bpf_event = (struct bpf_event){
159171
.header = {
160172
.type = PERF_RECORD_BPF_EVENT,
@@ -167,6 +179,22 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
167179
memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
168180
memset((void *)event + event->header.size, 0, machine->id_hdr_size);
169181
event->header.size += machine->id_hdr_size;
182+
183+
/* save bpf_prog_info to env */
184+
info_node = malloc(sizeof(struct bpf_prog_info_node));
185+
if (!info_node) {
186+
err = -1;
187+
goto out;
188+
}
189+
190+
info_node->info_linear = info_linear;
191+
perf_env__insert_bpf_prog_info(env, info_node);
192+
info_linear = NULL;
193+
194+
/*
195+
* process after saving bpf_prog_info to env, so that
196+
* required information is ready for look up
197+
*/
170198
err = perf_tool__process_synth_event(tool, event,
171199
machine, process);
172200
}

tools/perf/util/bpf-event.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
#define __PERF_BPF_EVENT_H
44

55
#include <linux/compiler.h>
6+
#include <linux/rbtree.h>
67
#include "event.h"
78

89
struct machine;
910
union perf_event;
1011
struct perf_sample;
11-
struct perf_tool;
1212
struct record_opts;
1313

14+
struct bpf_prog_info_node {
15+
struct bpf_prog_info_linear *info_linear;
16+
struct rb_node rb_node;
17+
};
18+
1419
#ifdef HAVE_LIBBPF_SUPPORT
1520
int machine__process_bpf_event(struct machine *machine, union perf_event *event,
1621
struct perf_sample *sample);

tools/perf/util/env.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,97 @@
33
#include "env.h"
44
#include "sane_ctype.h"
55
#include "util.h"
6+
#include "bpf-event.h"
67
#include <errno.h>
78
#include <sys/utsname.h>
9+
#include <bpf/libbpf.h>
810

911
struct perf_env perf_env;
1012

13+
void perf_env__insert_bpf_prog_info(struct perf_env *env,
14+
struct bpf_prog_info_node *info_node)
15+
{
16+
__u32 prog_id = info_node->info_linear->info.id;
17+
struct bpf_prog_info_node *node;
18+
struct rb_node *parent = NULL;
19+
struct rb_node **p;
20+
21+
down_write(&env->bpf_progs.lock);
22+
p = &env->bpf_progs.infos.rb_node;
23+
24+
while (*p != NULL) {
25+
parent = *p;
26+
node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
27+
if (prog_id < node->info_linear->info.id) {
28+
p = &(*p)->rb_left;
29+
} else if (prog_id > node->info_linear->info.id) {
30+
p = &(*p)->rb_right;
31+
} else {
32+
pr_debug("duplicated bpf prog info %u\n", prog_id);
33+
goto out;
34+
}
35+
}
36+
37+
rb_link_node(&info_node->rb_node, parent, p);
38+
rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
39+
env->bpf_progs.infos_cnt++;
40+
out:
41+
up_write(&env->bpf_progs.lock);
42+
}
43+
44+
struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
45+
__u32 prog_id)
46+
{
47+
struct bpf_prog_info_node *node = NULL;
48+
struct rb_node *n;
49+
50+
down_read(&env->bpf_progs.lock);
51+
n = env->bpf_progs.infos.rb_node;
52+
53+
while (n) {
54+
node = rb_entry(n, struct bpf_prog_info_node, rb_node);
55+
if (prog_id < node->info_linear->info.id)
56+
n = n->rb_left;
57+
else if (prog_id > node->info_linear->info.id)
58+
n = n->rb_right;
59+
else
60+
break;
61+
}
62+
63+
up_read(&env->bpf_progs.lock);
64+
return node;
65+
}
66+
67+
/* purge data in bpf_progs.infos tree */
68+
static void perf_env__purge_bpf(struct perf_env *env)
69+
{
70+
struct rb_root *root;
71+
struct rb_node *next;
72+
73+
down_write(&env->bpf_progs.lock);
74+
75+
root = &env->bpf_progs.infos;
76+
next = rb_first(root);
77+
78+
while (next) {
79+
struct bpf_prog_info_node *node;
80+
81+
node = rb_entry(next, struct bpf_prog_info_node, rb_node);
82+
next = rb_next(&node->rb_node);
83+
rb_erase(&node->rb_node, root);
84+
free(node);
85+
}
86+
87+
env->bpf_progs.infos_cnt = 0;
88+
89+
up_write(&env->bpf_progs.lock);
90+
}
91+
1192
void perf_env__exit(struct perf_env *env)
1293
{
1394
int i;
1495

96+
perf_env__purge_bpf(env);
1597
zfree(&env->hostname);
1698
zfree(&env->os_release);
1799
zfree(&env->version);
@@ -38,6 +120,12 @@ void perf_env__exit(struct perf_env *env)
38120
zfree(&env->memory_nodes);
39121
}
40122

123+
void perf_env__init(struct perf_env *env)
124+
{
125+
env->bpf_progs.infos = RB_ROOT;
126+
init_rwsem(&env->bpf_progs.lock);
127+
}
128+
41129
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
42130
{
43131
int i;

tools/perf/util/env.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#define __PERF_ENV_H
44

55
#include <linux/types.h>
6+
#include <linux/rbtree.h>
67
#include "cpumap.h"
8+
#include "rwsem.h"
79

810
struct cpu_topology_map {
911
int socket_id;
@@ -64,8 +66,20 @@ struct perf_env {
6466
struct memory_node *memory_nodes;
6567
unsigned long long memory_bsize;
6668
u64 clockid_res_ns;
69+
70+
/*
71+
* bpf_info_lock protects bpf rbtrees. This is needed because the
72+
* trees are accessed by different threads in perf-top
73+
*/
74+
struct {
75+
struct rw_semaphore lock;
76+
struct rb_root infos;
77+
u32 infos_cnt;
78+
} bpf_progs;
6779
};
6880

81+
struct bpf_prog_info_node;
82+
6983
extern struct perf_env perf_env;
7084

7185
void perf_env__exit(struct perf_env *env);
@@ -80,4 +94,9 @@ const char *perf_env__arch(struct perf_env *env);
8094
const char *perf_env__raw_arch(struct perf_env *env);
8195
int perf_env__nr_cpus_avail(struct perf_env *env);
8296

97+
void perf_env__init(struct perf_env *env);
98+
void perf_env__insert_bpf_prog_info(struct perf_env *env,
99+
struct bpf_prog_info_node *info_node);
100+
struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
101+
__u32 prog_id);
83102
#endif /* __PERF_ENV_H */

tools/perf/util/session.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
132132
ordered_events__init(&session->ordered_events,
133133
ordered_events__deliver_event, NULL);
134134

135+
perf_env__init(&session->header.env);
135136
if (data) {
136137
if (perf_data__open(data))
137138
goto out_delete;

0 commit comments

Comments
 (0)