lkml.org 
[lkml]   [2019]   [Mar]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v8 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
    Date
    This patch enables perf-record to save bpf_prog_info information as
    headers to perf.data. A new header type HEADER_BPF_PROG_INFO is
    introduced for this data.

    Signed-off-by: Song Liu <songliubraving@fb.com>
    ---
    tools/perf/util/header.c | 139 ++++++++++++++++++++++++++++++++++++++-
    tools/perf/util/header.h | 1 +
    2 files changed, 139 insertions(+), 1 deletion(-)

    diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
    index 4b88de5e9192..e53ee3111430 100644
    --- a/tools/perf/util/header.c
    +++ b/tools/perf/util/header.c
    @@ -18,6 +18,7 @@
    #include <sys/utsname.h>
    #include <linux/time64.h>
    #include <dirent.h>
    +#include <bpf/libbpf.h>

    #include "evlist.h"
    #include "evsel.h"
    @@ -39,6 +40,7 @@
    #include "tool.h"
    #include "time-utils.h"
    #include "units.h"
    +#include "bpf-event.h"

    #include "sane_ctype.h"

    @@ -1074,6 +1076,48 @@ static int write_clockid(struct feat_fd *ff,
    sizeof(ff->ph->env.clockid_res_ns));
    }

    +static int write_bpf_prog_info(struct feat_fd *ff,
    + struct perf_evlist *evlist __maybe_unused)
    +{
    + struct perf_env *env = &ff->ph->env;
    + struct rb_root *root;
    + struct rb_node *next;
    + int ret;
    +
    + down_read(&env->bpf_progs.lock);
    +
    + ret = do_write(ff, &env->bpf_progs.infos_cnt,
    + sizeof(env->bpf_progs.infos_cnt));
    + if (ret < 0)
    + goto out;
    +
    + root = &env->bpf_progs.infos;
    + next = rb_first(root);
    + while (next) {
    + struct bpf_prog_info_node *node;
    + size_t len;
    +
    + node = rb_entry(next, struct bpf_prog_info_node, rb_node);
    + next = rb_next(&node->rb_node);
    + len = sizeof(struct bpf_prog_info_linear) +
    + node->info_linear->data_len;
    +
    + /* before writing to file, translate address to offset */
    + bpf_program__bpil_addr_to_offs(node->info_linear);
    + ret = do_write(ff, node->info_linear, len);
    + /*
    + * translate back to address even when do_write() fails,
    + * so that this function never changes the data.
    + */
    + bpf_program__bpil_offs_to_addr(node->info_linear);
    + if (ret < 0)
    + goto out;
    + }
    +out:
    + up_read(&env->bpf_progs.lock);
    + return ret;
    +}
    +
    static int cpu_cache_level__sort(const void *a, const void *b)
    {
    struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
    @@ -1554,6 +1598,29 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
    ff->ph->env.clockid_res_ns * 1000);
    }

    +static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
    +{
    + struct perf_env *env = &ff->ph->env;
    + struct rb_root *root;
    + struct rb_node *next;
    +
    + down_read(&env->bpf_progs.lock);
    +
    + root = &env->bpf_progs.infos;
    + next = rb_first(root);
    +
    + while (next) {
    + struct bpf_prog_info_node *node;
    +
    + node = rb_entry(next, struct bpf_prog_info_node, rb_node);
    + next = rb_next(&node->rb_node);
    + fprintf(fp, "# bpf_prog_info of id %u\n",
    + node->info_linear->info.id);
    + }
    +
    + up_read(&env->bpf_progs.lock);
    +}
    +
    static void free_event_desc(struct perf_evsel *events)
    {
    struct perf_evsel *evsel;
    @@ -2586,6 +2653,75 @@ static int process_clockid(struct feat_fd *ff,
    return 0;
    }

    +static int process_bpf_prog_info(struct feat_fd *ff,
    + void *data __maybe_unused)
    +{
    + struct bpf_prog_info_linear *info_linear;
    + struct bpf_prog_info_node *info_node;
    + struct perf_env *env = &ff->ph->env;
    + u32 count, i;
    + int err = -1;
    +
    + if (ff->ph->needs_swap) {
    + pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
    + return 0;
    + }
    +
    + if (do_read_u32(ff, &count))
    + return -1;
    +
    + down_write(&env->bpf_progs.lock);
    +
    + for (i = 0; i < count; ++i) {
    + u32 info_len, data_len;
    +
    + info_linear = NULL;
    + info_node = NULL;
    + if (do_read_u32(ff, &info_len))
    + goto out;
    + if (do_read_u32(ff, &data_len))
    + goto out;
    +
    + if (info_len > sizeof(struct bpf_prog_info)) {
    + pr_warning("detected invalid bpf_prog_info\n");
    + goto out;
    + }
    +
    + info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
    + data_len);
    + if (!info_linear)
    + goto out;
    + info_linear->info_len = sizeof(struct bpf_prog_info);
    + info_linear->data_len = data_len;
    + if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
    + goto out;
    + if (__do_read(ff, &info_linear->info, info_len))
    + goto out;
    + if (info_len < sizeof(struct bpf_prog_info))
    + memset(((void *)(&info_linear->info)) + info_len, 0,
    + sizeof(struct bpf_prog_info) - info_len);
    +
    + if (__do_read(ff, info_linear->data, data_len))
    + goto out;
    +
    + info_node = malloc(sizeof(struct bpf_prog_info_node));
    + if (!info_node)
    + goto out;
    +
    + /* after reading from file, translate offset to address */
    + bpf_program__bpil_offs_to_addr(info_linear);
    + info_node->info_linear = info_linear;
    + perf_env__insert_bpf_prog_info(env, info_node);
    + }
    +
    + return 0;
    +out:
    + free(info_linear);
    + free(info_node);
    + up_write(&env->bpf_progs.lock);
    + return err;
    +}
    +
    struct feature_ops {
    int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
    void (*print)(struct feat_fd *ff, FILE *fp);
    @@ -2645,7 +2781,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
    FEAT_OPN(CACHE, cache, true),
    FEAT_OPR(SAMPLE_TIME, sample_time, false),
    FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
    - FEAT_OPR(CLOCKID, clockid, false)
    + FEAT_OPR(CLOCKID, clockid, false),
    + FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
    };

    struct header_print_data {
    diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
    index 0d553ddca0a3..0785c91b4c3a 100644
    --- a/tools/perf/util/header.h
    +++ b/tools/perf/util/header.h
    @@ -39,6 +39,7 @@ enum {
    HEADER_SAMPLE_TIME,
    HEADER_MEM_TOPOLOGY,
    HEADER_CLOCKID,
    + HEADER_BPF_PROG_INFO,
    HEADER_LAST_FEATURE,
    HEADER_FEAT_BITS = 256,
    };
    --
    2.17.1
    \
     
     \ /
      Last update: 2019-03-11 21:10    [W:7.614 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site