lkml.org 
[lkml]   [2019]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs
    Date
    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 short living BPF programs. 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. These information are saved to perf.data at the end of
    perf-record.

    Signed-off-by: Song Liu <songliubraving@fb.com>
    ---
    tools/perf/builtin-record.c | 2 +
    tools/perf/builtin-top.c | 2 +
    tools/perf/util/bpf-event.c | 95 +++++++++++++++++++++++++++++++++++++
    tools/perf/util/bpf-event.h | 15 ++++++
    4 files changed, 114 insertions(+)

    diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
    index f792dd28d936..3c0596a68992 100644
    --- a/tools/perf/builtin-record.c
    +++ b/tools/perf/builtin-record.c
    @@ -1217,6 +1217,8 @@ 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);
    perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);

    err = record__synthesize(rec, false);
    diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
    index 9577dba4996b..b7790d66cac2 100644
    --- a/tools/perf/builtin-top.c
    +++ b/tools/perf/builtin-top.c
    @@ -1641,6 +1641,8 @@ int cmd_top(int argc, const char **argv)
    signal(SIGWINCH, winch_sig);
    }

    + if (!top.record_opts.no_bpf_event)
    + bpf_event__add_sb_event(&sb_evlist, &perf_env);
    perf_evlist__start_sb_thread(sb_evlist, target);

    status = __cmd_top(&top);
    diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
    index af434de3a23e..77e0fdead6f4 100644
    --- a/tools/perf/util/bpf-event.c
    +++ b/tools/perf/util/bpf-event.c
    @@ -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,97 @@ 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,
    + .wakeup_watermark = 1,
    + .size = sizeof(attr), /* to capture ABI version */
    + };
    +
    + return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
    +}
    diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
    index b9ec394dc7c7..249909c826e7 100644
    --- a/tools/perf/util/bpf-event.h
    +++ b/tools/perf/util/bpf-event.h
    @@ -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 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
    --
    2.17.1
    \
     
     \ /
      Last update: 2019-03-12 06:32    [W:2.697 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site