mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
perf tools: Save bpf_prog_info and BTF of new BPF programs
To fully annotate BPF programs with source code mapping, 4 different information are needed: 1) PERF_RECORD_KSYMBOL 2) PERF_RECORD_BPF_EVENT 3) bpf_prog_info 4) btf This patch handles 3) and 4) for BPF programs loaded after 'perf record|top'. For timely process of these information, a dedicated event is added to the side band evlist. When PERF_RECORD_BPF_EVENT is received via the side band event, the polling thread gathers 3) and 4) vis sys_bpf and store them in perf_env. This information is saved to perf.data at the end of 'perf record'. Committer testing: The 'wakeup_watermark' member in 'struct perf_event_attr' is inside a unnamed union, so can't be used in a struct designated initialization with older gccs, get it out of that, isolating as 'attr.wakeup_watermark = 1;' to work with all gcc versions. We also need to add '--no-bpf-event' to the 'perf record' perf_event_attr tests in 'perf test', as the way that that test goes is to intercept the events being setup and looking if they match the fields described in the control files, since now it finds first the side band event used to catch the PERF_RECORD_BPF_EVENT, they all fail. With these issues fixed: Same scenario as for testing BPF programs loaded before 'perf record' or 'perf top' starts, only start the BPF programs after 'perf record|top', so that its information get collected by the sideband threads, the rest works as for the programs loaded before start monitoring. Add missing 'inline' to the bpf_event__add_sb_event() when HAVE_LIBBPF_SUPPORT is not defined, fixing the build in systems without binutils devel files installed. Signed-off-by: Song Liu <songliubraving@fb.com> Reviewed-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stanislav Fomichev <sdf@google.com> Link: http://lkml.kernel.org/r/20190312053051.2690567-16-songliubraving@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
657ee55319
commit
d56354dc49
@ -1238,6 +1238,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
||||
goto out_child;
|
||||
}
|
||||
|
||||
if (!opts->no_bpf_event)
|
||||
bpf_event__add_sb_event(&sb_evlist, &session->header.env);
|
||||
|
||||
if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
|
||||
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
|
||||
opts->no_bpf_event = true;
|
||||
|
@ -1637,6 +1637,9 @@ int cmd_top(int argc, const char **argv)
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
if (!top.record_opts.no_bpf_event)
|
||||
bpf_event__add_sb_event(&sb_evlist, &perf_env);
|
||||
|
||||
if (perf_evlist__start_sb_thread(sb_evlist, target)) {
|
||||
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
|
||||
opts->no_bpf_event = true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -C 0 kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -C 0 kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = kill >/dev/null 2>&1
|
||||
args = --no-bpf-event kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -b kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -b kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j any kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j any kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j any_call kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j any_call kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j any_ret kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j any_ret kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j hv kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j hv kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j ind_call kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j ind_call kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j k kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j k kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -j u kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -j u kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -c 123 kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -c 123 kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -d kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -d kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -F 100 kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -F 100 kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -g kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -g kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = --call-graph dwarf -- kill >/dev/null 2>&1
|
||||
args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = --call-graph fp kill >/dev/null 2>&1
|
||||
args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = --group -e cycles,instructions kill >/dev/null 2>&1
|
||||
args = --no-bpf-event --group -e cycles,instructions kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event-1:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event-1:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -e '{cycles,instructions}' kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event-1:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = --no-buffering kill >/dev/null 2>&1
|
||||
args = --no-bpf-event --no-buffering kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -i kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -i kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -n kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -n kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -c 100 -P kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -c 100 -P kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[config]
|
||||
command = record
|
||||
args = -R kill >/dev/null 2>&1
|
||||
args = --no-bpf-event -R kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
|
||||
[event:base-record]
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "env.h"
|
||||
#include "session.h"
|
||||
#include "map.h"
|
||||
#include "evlist.h"
|
||||
|
||||
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
|
||||
|
||||
@ -330,3 +331,102 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
|
||||
free(event);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
|
||||
{
|
||||
struct bpf_prog_info_linear *info_linear;
|
||||
struct bpf_prog_info_node *info_node;
|
||||
struct btf *btf = NULL;
|
||||
u64 arrays;
|
||||
u32 btf_id;
|
||||
int fd;
|
||||
|
||||
fd = bpf_prog_get_fd_by_id(id);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
|
||||
arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
|
||||
arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
|
||||
arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
|
||||
arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
|
||||
arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
|
||||
arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
|
||||
|
||||
info_linear = bpf_program__get_prog_info_linear(fd, arrays);
|
||||
if (IS_ERR_OR_NULL(info_linear)) {
|
||||
pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
btf_id = info_linear->info.btf_id;
|
||||
|
||||
info_node = malloc(sizeof(struct bpf_prog_info_node));
|
||||
if (info_node) {
|
||||
info_node->info_linear = info_linear;
|
||||
perf_env__insert_bpf_prog_info(env, info_node);
|
||||
} else
|
||||
free(info_linear);
|
||||
|
||||
if (btf_id == 0)
|
||||
goto out;
|
||||
|
||||
if (btf__get_from_id(btf_id, &btf)) {
|
||||
pr_debug("%s: failed to get BTF of id %u, aborting\n",
|
||||
__func__, btf_id);
|
||||
goto out;
|
||||
}
|
||||
perf_env__fetch_btf(env, btf_id, btf);
|
||||
|
||||
out:
|
||||
free(btf);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int bpf_event__sb_cb(union perf_event *event, void *data)
|
||||
{
|
||||
struct perf_env *env = data;
|
||||
|
||||
if (event->header.type != PERF_RECORD_BPF_EVENT)
|
||||
return -1;
|
||||
|
||||
switch (event->bpf_event.type) {
|
||||
case PERF_BPF_EVENT_PROG_LOAD:
|
||||
perf_env__add_bpf_info(env, event->bpf_event.id);
|
||||
|
||||
case PERF_BPF_EVENT_PROG_UNLOAD:
|
||||
/*
|
||||
* Do not free bpf_prog_info and btf of the program here,
|
||||
* as annotation still need them. They will be freed at
|
||||
* the end of the session.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
pr_debug("unexpected bpf_event type of %d\n",
|
||||
event->bpf_event.type);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_event__add_sb_event(struct perf_evlist **evlist,
|
||||
struct perf_env *env)
|
||||
{
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_SOFTWARE,
|
||||
.config = PERF_COUNT_SW_DUMMY,
|
||||
.sample_id_all = 1,
|
||||
.watermark = 1,
|
||||
.bpf_event = 1,
|
||||
.size = sizeof(attr), /* to capture ABI version */
|
||||
};
|
||||
|
||||
/*
|
||||
* Older gcc versions don't support designated initializers, like above,
|
||||
* for unnamed union members, such as the following:
|
||||
*/
|
||||
attr.wakeup_watermark = 1;
|
||||
|
||||
return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
|
||||
}
|
||||
|
@ -4,12 +4,17 @@
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <pthread.h>
|
||||
#include <api/fd/array.h>
|
||||
#include "event.h"
|
||||
|
||||
struct machine;
|
||||
union perf_event;
|
||||
struct perf_env;
|
||||
struct perf_sample;
|
||||
struct record_opts;
|
||||
struct evlist;
|
||||
struct target;
|
||||
|
||||
struct bpf_prog_info_node {
|
||||
struct bpf_prog_info_linear *info_linear;
|
||||
@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
|
||||
perf_event__handler_t process,
|
||||
struct machine *machine,
|
||||
struct record_opts *opts);
|
||||
int bpf_event__add_sb_event(struct perf_evlist **evlist,
|
||||
struct perf_env *env);
|
||||
|
||||
#else
|
||||
static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
@ -46,5 +54,12 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
|
||||
struct perf_env *env __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_LIBBPF_SUPPORT
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user