diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/perf.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/bpf-event.c | 30 | ||||
| -rw-r--r-- | tools/perf/util/bpf-event.h | 7 | ||||
| -rw-r--r-- | tools/perf/util/env.c | 88 | ||||
| -rw-r--r-- | tools/perf/util/env.h | 19 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 1 |
6 files changed, 144 insertions, 2 deletions
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index a11cb006f968..72df4b6fa36f 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
| 298 | use_pager = 1; | 298 | use_pager = 1; |
| 299 | commit_pager_choice(); | 299 | commit_pager_choice(); |
| 300 | 300 | ||
| 301 | perf_env__init(&perf_env); | ||
| 301 | perf_env__set_cmdline(&perf_env, argc, argv); | 302 | perf_env__set_cmdline(&perf_env, argc, argv); |
| 302 | status = p->fn(argc, argv); | 303 | status = p->fn(argc, argv); |
| 303 | perf_config__exit(); | 304 | perf_config__exit(); |
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 5237e8f11997..37ee4e2a728a 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "debug.h" | 10 | #include "debug.h" |
| 11 | #include "symbol.h" | 11 | #include "symbol.h" |
| 12 | #include "machine.h" | 12 | #include "machine.h" |
| 13 | #include "env.h" | ||
| 13 | #include "session.h" | 14 | #include "session.h" |
| 14 | 15 | ||
| 15 | #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) | 16 | #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, | |||
| 54 | struct bpf_event *bpf_event = &event->bpf_event; | 55 | struct bpf_event *bpf_event = &event->bpf_event; |
| 55 | struct bpf_prog_info_linear *info_linear; | 56 | struct bpf_prog_info_linear *info_linear; |
| 56 | struct perf_tool *tool = session->tool; | 57 | struct perf_tool *tool = session->tool; |
| 58 | struct bpf_prog_info_node *info_node; | ||
| 57 | struct bpf_prog_info *info; | 59 | struct bpf_prog_info *info; |
| 58 | struct btf *btf = NULL; | 60 | struct btf *btf = NULL; |
| 59 | bool has_btf = false; | 61 | bool has_btf = false; |
| 62 | struct perf_env *env; | ||
| 60 | u32 sub_prog_cnt, i; | 63 | u32 sub_prog_cnt, i; |
| 61 | int err = 0; | 64 | int err = 0; |
| 62 | u64 arrays; | 65 | u64 arrays; |
| 63 | 66 | ||
| 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 | |||
| 64 | arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS; | 73 | arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS; |
| 65 | arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; | 74 | arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; |
| 66 | arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; | 75 | arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; |
| 67 | arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS; | 76 | 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; | ||
| 68 | 80 | ||
| 69 | info_linear = bpf_program__get_prog_info_linear(fd, arrays); | 81 | info_linear = bpf_program__get_prog_info_linear(fd, arrays); |
| 70 | if (IS_ERR_OR_NULL(info_linear)) { | 82 | if (IS_ERR_OR_NULL(info_linear)) { |
| @@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, | |||
| 153 | machine, process); | 165 | machine, process); |
| 154 | } | 166 | } |
| 155 | 167 | ||
| 156 | /* Synthesize PERF_RECORD_BPF_EVENT */ | ||
| 157 | if (!opts->no_bpf_event) { | 168 | if (!opts->no_bpf_event) { |
| 169 | /* Synthesize PERF_RECORD_BPF_EVENT */ | ||
| 158 | *bpf_event = (struct bpf_event){ | 170 | *bpf_event = (struct bpf_event){ |
| 159 | .header = { | 171 | .header = { |
| 160 | .type = PERF_RECORD_BPF_EVENT, | 172 | .type = PERF_RECORD_BPF_EVENT, |
| @@ -167,6 +179,22 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, | |||
| 167 | memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE); | 179 | memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE); |
| 168 | memset((void *)event + event->header.size, 0, machine->id_hdr_size); | 180 | memset((void *)event + event->header.size, 0, machine->id_hdr_size); |
| 169 | event->header.size += machine->id_hdr_size; | 181 | 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 | */ | ||
| 170 | err = perf_tool__process_synth_event(tool, event, | 198 | err = perf_tool__process_synth_event(tool, event, |
| 171 | machine, process); | 199 | machine, process); |
| 172 | } | 200 | } |
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h index 6698683612a7..fad932f7404f 100644 --- a/tools/perf/util/bpf-event.h +++ b/tools/perf/util/bpf-event.h | |||
| @@ -3,14 +3,19 @@ | |||
| 3 | #define __PERF_BPF_EVENT_H | 3 | #define __PERF_BPF_EVENT_H |
| 4 | 4 | ||
| 5 | #include <linux/compiler.h> | 5 | #include <linux/compiler.h> |
| 6 | #include <linux/rbtree.h> | ||
| 6 | #include "event.h" | 7 | #include "event.h" |
| 7 | 8 | ||
| 8 | struct machine; | 9 | struct machine; |
| 9 | union perf_event; | 10 | union perf_event; |
| 10 | struct perf_sample; | 11 | struct perf_sample; |
| 11 | struct perf_tool; | ||
| 12 | struct record_opts; | 12 | struct record_opts; |
| 13 | 13 | ||
| 14 | struct bpf_prog_info_node { | ||
| 15 | struct bpf_prog_info_linear *info_linear; | ||
| 16 | struct rb_node rb_node; | ||
| 17 | }; | ||
| 18 | |||
| 14 | #ifdef HAVE_LIBBPF_SUPPORT | 19 | #ifdef HAVE_LIBBPF_SUPPORT |
| 15 | int machine__process_bpf_event(struct machine *machine, union perf_event *event, | 20 | int machine__process_bpf_event(struct machine *machine, union perf_event *event, |
| 16 | struct perf_sample *sample); | 21 | struct perf_sample *sample); |
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 4c23779e271a..98cd36f0e317 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c | |||
| @@ -3,15 +3,97 @@ | |||
| 3 | #include "env.h" | 3 | #include "env.h" |
| 4 | #include "sane_ctype.h" | 4 | #include "sane_ctype.h" |
| 5 | #include "util.h" | 5 | #include "util.h" |
| 6 | #include "bpf-event.h" | ||
| 6 | #include <errno.h> | 7 | #include <errno.h> |
| 7 | #include <sys/utsname.h> | 8 | #include <sys/utsname.h> |
| 9 | #include <bpf/libbpf.h> | ||
| 8 | 10 | ||
| 9 | struct perf_env perf_env; | 11 | struct perf_env perf_env; |
| 10 | 12 | ||
| 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 | |||
| 11 | void perf_env__exit(struct perf_env *env) | 92 | void perf_env__exit(struct perf_env *env) |
| 12 | { | 93 | { |
| 13 | int i; | 94 | int i; |
| 14 | 95 | ||
| 96 | perf_env__purge_bpf(env); | ||
| 15 | zfree(&env->hostname); | 97 | zfree(&env->hostname); |
| 16 | zfree(&env->os_release); | 98 | zfree(&env->os_release); |
| 17 | zfree(&env->version); | 99 | zfree(&env->version); |
| @@ -38,6 +120,12 @@ void perf_env__exit(struct perf_env *env) | |||
| 38 | zfree(&env->memory_nodes); | 120 | zfree(&env->memory_nodes); |
| 39 | } | 121 | } |
| 40 | 122 | ||
| 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 | |||
| 41 | int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) | 129 | int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) |
| 42 | { | 130 | { |
| 43 | int i; | 131 | int i; |
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index d01b8355f4ca..24b11c564ba4 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h | |||
| @@ -3,7 +3,9 @@ | |||
| 3 | #define __PERF_ENV_H | 3 | #define __PERF_ENV_H |
| 4 | 4 | ||
| 5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
| 6 | #include <linux/rbtree.h> | ||
| 6 | #include "cpumap.h" | 7 | #include "cpumap.h" |
| 8 | #include "rwsem.h" | ||
| 7 | 9 | ||
| 8 | struct cpu_topology_map { | 10 | struct cpu_topology_map { |
| 9 | int socket_id; | 11 | int socket_id; |
| @@ -64,8 +66,20 @@ struct perf_env { | |||
| 64 | struct memory_node *memory_nodes; | 66 | struct memory_node *memory_nodes; |
| 65 | unsigned long long memory_bsize; | 67 | unsigned long long memory_bsize; |
| 66 | u64 clockid_res_ns; | 68 | 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; | ||
| 67 | }; | 79 | }; |
| 68 | 80 | ||
| 81 | struct bpf_prog_info_node; | ||
| 82 | |||
| 69 | extern struct perf_env perf_env; | 83 | extern struct perf_env perf_env; |
| 70 | 84 | ||
| 71 | void perf_env__exit(struct perf_env *env); | 85 | void perf_env__exit(struct perf_env *env); |
| @@ -80,4 +94,9 @@ const char *perf_env__arch(struct perf_env *env); | |||
| 80 | const char *perf_env__raw_arch(struct perf_env *env); | 94 | const char *perf_env__raw_arch(struct perf_env *env); |
| 81 | int perf_env__nr_cpus_avail(struct perf_env *env); | 95 | int perf_env__nr_cpus_avail(struct perf_env *env); |
| 82 | 96 | ||
| 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); | ||
| 83 | #endif /* __PERF_ENV_H */ | 102 | #endif /* __PERF_ENV_H */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0ec34227bd60..b17f1c9bc965 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -132,6 +132,7 @@ struct perf_session *perf_session__new(struct perf_data *data, | |||
| 132 | ordered_events__init(&session->ordered_events, | 132 | ordered_events__init(&session->ordered_events, |
| 133 | ordered_events__deliver_event, NULL); | 133 | ordered_events__deliver_event, NULL); |
| 134 | 134 | ||
| 135 | perf_env__init(&session->header.env); | ||
| 135 | if (data) { | 136 | if (data) { |
| 136 | if (perf_data__open(data)) | 137 | if (perf_data__open(data)) |
| 137 | goto out_delete; | 138 | goto out_delete; |
