* [PATCH v2 perf,bpf 03/11] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 04/11] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
` (5 subsequent siblings)
6 siblings, 0 replies; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
This patches uses bpf_program__get_prog_info_linear() to simplify the
logic in prog.c do_dump().
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/bpf/bpftool/prog.c | 266 +++++++++------------------------------
1 file changed, 59 insertions(+), 207 deletions(-)
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 0640e9bc0ada..206b820df7c2 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -393,41 +393,31 @@ static int do_show(int argc, char **argv)
static int do_dump(int argc, char **argv)
{
- unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size;
- void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL;
- unsigned int nr_finfo, nr_linfo = 0, nr_jited_linfo = 0;
+ struct bpf_prog_info_linear *info_linear;
struct bpf_prog_linfo *prog_linfo = NULL;
- unsigned long *func_ksyms = NULL;
- struct bpf_prog_info info = {};
- unsigned int *func_lens = NULL;
+ enum {DUMP_JITED, DUMP_XLATED} mode;
const char *disasm_opt = NULL;
- unsigned int nr_func_ksyms;
- unsigned int nr_func_lens;
+ struct bpf_prog_info *info;
struct dump_data dd = {};
- __u32 len = sizeof(info);
+ void *func_info = NULL;
struct btf *btf = NULL;
- unsigned int buf_size;
char *filepath = NULL;
bool opcodes = false;
bool visual = false;
char func_sig[1024];
unsigned char *buf;
bool linum = false;
- __u32 *member_len;
- __u64 *member_ptr;
+ __u32 member_len;
+ __u64 arrays;
ssize_t n;
- int err;
int fd;
if (is_prefix(*argv, "jited")) {
if (disasm_init())
return -1;
-
- member_len = &info.jited_prog_len;
- member_ptr = &info.jited_prog_insns;
+ mode = DUMP_JITED;
} else if (is_prefix(*argv, "xlated")) {
- member_len = &info.xlated_prog_len;
- member_ptr = &info.xlated_prog_insns;
+ mode = DUMP_XLATED;
} else {
p_err("expected 'xlated' or 'jited', got: %s", *argv);
return -1;
@@ -466,175 +456,50 @@ static int do_dump(int argc, char **argv)
return -1;
}
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
- if (err) {
- p_err("can't get prog info: %s", strerror(errno));
- return -1;
- }
-
- if (!*member_len) {
- p_info("no instructions returned");
- close(fd);
- return 0;
- }
+ if (mode == DUMP_JITED)
+ arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
+ else
+ arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;
- buf_size = *member_len;
+ 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_LINE_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
- buf = malloc(buf_size);
- if (!buf) {
- p_err("mem alloc failed");
- close(fd);
+ info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+ close(fd);
+ if (IS_ERR_OR_NULL(info_linear)) {
+ p_err("can't get prog info: %s", strerror(errno));
return -1;
}
- nr_func_ksyms = info.nr_jited_ksyms;
- if (nr_func_ksyms) {
- func_ksyms = malloc(nr_func_ksyms * sizeof(__u64));
- if (!func_ksyms) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- nr_func_lens = info.nr_jited_func_lens;
- if (nr_func_lens) {
- func_lens = malloc(nr_func_lens * sizeof(__u32));
- if (!func_lens) {
- p_err("mem alloc failed");
- close(fd);
+ info = &info_linear->info;
+ if (mode == DUMP_JITED) {
+ if (info->jited_prog_len == 0) {
+ p_info("no instructions returned");
goto err_free;
}
- }
-
- nr_finfo = info.nr_func_info;
- finfo_rec_size = info.func_info_rec_size;
- if (nr_finfo && finfo_rec_size) {
- func_info = malloc(nr_finfo * finfo_rec_size);
- if (!func_info) {
- p_err("mem alloc failed");
- close(fd);
+ buf = (unsigned char *)(info->jited_prog_insns);
+ member_len = info->jited_prog_len;
+ } else { /* DUMP_XLATED */
+ if (info->xlated_prog_len == 0) {
+ p_err("error retrieving insn dump: kernel.kptr_restrict set?");
goto err_free;
}
+ buf = (unsigned char *)info->xlated_prog_insns;
+ member_len = info->xlated_prog_len;
}
- linfo_rec_size = info.line_info_rec_size;
- if (info.nr_line_info && linfo_rec_size && info.btf_id) {
- nr_linfo = info.nr_line_info;
- linfo = malloc(nr_linfo * linfo_rec_size);
- if (!linfo) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- jited_linfo_rec_size = info.jited_line_info_rec_size;
- if (info.nr_jited_line_info &&
- jited_linfo_rec_size &&
- info.nr_jited_ksyms &&
- info.nr_jited_func_lens &&
- info.btf_id) {
- nr_jited_linfo = info.nr_jited_line_info;
- jited_linfo = malloc(nr_jited_linfo * jited_linfo_rec_size);
- if (!jited_linfo) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- memset(&info, 0, sizeof(info));
-
- *member_ptr = ptr_to_u64(buf);
- *member_len = buf_size;
- info.jited_ksyms = ptr_to_u64(func_ksyms);
- info.nr_jited_ksyms = nr_func_ksyms;
- info.jited_func_lens = ptr_to_u64(func_lens);
- info.nr_jited_func_lens = nr_func_lens;
- info.nr_func_info = nr_finfo;
- info.func_info_rec_size = finfo_rec_size;
- info.func_info = ptr_to_u64(func_info);
- info.nr_line_info = nr_linfo;
- info.line_info_rec_size = linfo_rec_size;
- info.line_info = ptr_to_u64(linfo);
- info.nr_jited_line_info = nr_jited_linfo;
- info.jited_line_info_rec_size = jited_linfo_rec_size;
- info.jited_line_info = ptr_to_u64(jited_linfo);
-
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
- close(fd);
- if (err) {
- p_err("can't get prog info: %s", strerror(errno));
- goto err_free;
- }
-
- if (*member_len > buf_size) {
- p_err("too many instructions returned");
- goto err_free;
- }
-
- if (info.nr_jited_ksyms > nr_func_ksyms) {
- p_err("too many addresses returned");
- goto err_free;
- }
-
- if (info.nr_jited_func_lens > nr_func_lens) {
- p_err("too many values returned");
- goto err_free;
- }
-
- if (info.nr_func_info != nr_finfo) {
- p_err("incorrect nr_func_info %d vs. expected %d",
- info.nr_func_info, nr_finfo);
- goto err_free;
- }
-
- if (info.func_info_rec_size != finfo_rec_size) {
- p_err("incorrect func_info_rec_size %d vs. expected %d",
- info.func_info_rec_size, finfo_rec_size);
- goto err_free;
- }
-
- if (linfo && info.nr_line_info != nr_linfo) {
- p_err("incorrect nr_line_info %u vs. expected %u",
- info.nr_line_info, nr_linfo);
- goto err_free;
- }
-
- if (info.line_info_rec_size != linfo_rec_size) {
- p_err("incorrect line_info_rec_size %u vs. expected %u",
- info.line_info_rec_size, linfo_rec_size);
- goto err_free;
- }
-
- if (jited_linfo && info.nr_jited_line_info != nr_jited_linfo) {
- p_err("incorrect nr_jited_line_info %u vs. expected %u",
- info.nr_jited_line_info, nr_jited_linfo);
- goto err_free;
- }
-
- if (info.jited_line_info_rec_size != jited_linfo_rec_size) {
- p_err("incorrect jited_line_info_rec_size %u vs. expected %u",
- info.jited_line_info_rec_size, jited_linfo_rec_size);
- goto err_free;
- }
-
- if ((member_len == &info.jited_prog_len &&
- info.jited_prog_insns == 0) ||
- (member_len == &info.xlated_prog_len &&
- info.xlated_prog_insns == 0)) {
- p_err("error retrieving insn dump: kernel.kptr_restrict set?");
- goto err_free;
- }
-
- if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) {
+ if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) {
p_err("failed to get btf");
goto err_free;
}
- if (nr_linfo) {
- prog_linfo = bpf_prog_linfo__new(&info);
+ func_info = (void *)info->func_info;
+
+ if (info->nr_line_info) {
+ prog_linfo = bpf_prog_linfo__new(info);
if (!prog_linfo)
p_info("error in processing bpf_line_info. continue without it.");
}
@@ -647,9 +512,9 @@ static int do_dump(int argc, char **argv)
goto err_free;
}
- n = write(fd, buf, *member_len);
+ n = write(fd, buf, member_len);
close(fd);
- if (n != *member_len) {
+ if (n != member_len) {
p_err("error writing output file: %s",
n < 0 ? strerror(errno) : "short write");
goto err_free;
@@ -657,19 +522,19 @@ static int do_dump(int argc, char **argv)
if (json_output)
jsonw_null(json_wtr);
- } else if (member_len == &info.jited_prog_len) {
+ } else if (mode == DUMP_JITED) {
const char *name = NULL;
- if (info.ifindex) {
- name = ifindex_to_bfd_params(info.ifindex,
- info.netns_dev,
- info.netns_ino,
+ if (info->ifindex) {
+ name = ifindex_to_bfd_params(info->ifindex,
+ info->netns_dev,
+ info->netns_ino,
&disasm_opt);
if (!name)
goto err_free;
}
- if (info.nr_jited_func_lens && info.jited_func_lens) {
+ if (info->nr_jited_func_lens && info->jited_func_lens) {
struct kernel_sym *sym = NULL;
struct bpf_func_info *record;
char sym_name[SYM_MAX_NAME];
@@ -677,17 +542,16 @@ static int do_dump(int argc, char **argv)
__u64 *ksyms = NULL;
__u32 *lens;
__u32 i;
-
- if (info.nr_jited_ksyms) {
+ if (info->nr_jited_ksyms) {
kernel_syms_load(&dd);
- ksyms = (__u64 *) info.jited_ksyms;
+ ksyms = (__u64 *) info->jited_ksyms;
}
if (json_output)
jsonw_start_array(json_wtr);
- lens = (__u32 *) info.jited_func_lens;
- for (i = 0; i < info.nr_jited_func_lens; i++) {
+ lens = (__u32 *) info->jited_func_lens;
+ for (i = 0; i < info->nr_jited_func_lens; i++) {
if (ksyms) {
sym = kernel_syms_search(&dd, ksyms[i]);
if (sym)
@@ -699,7 +563,7 @@ static int do_dump(int argc, char **argv)
}
if (func_info) {
- record = func_info + i * finfo_rec_size;
+ record = func_info + i * info->func_info_rec_size;
btf_dumper_type_only(btf, record->type_id,
func_sig,
sizeof(func_sig));
@@ -736,49 +600,37 @@ static int do_dump(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
} else {
- disasm_print_insn(buf, *member_len, opcodes, name,
+ disasm_print_insn(buf, member_len, opcodes, name,
disasm_opt, btf, NULL, 0, 0, false);
}
} else if (visual) {
if (json_output)
jsonw_null(json_wtr);
else
- dump_xlated_cfg(buf, *member_len);
+ dump_xlated_cfg(buf, member_len);
} else {
kernel_syms_load(&dd);
- dd.nr_jited_ksyms = info.nr_jited_ksyms;
- dd.jited_ksyms = (__u64 *) info.jited_ksyms;
+ dd.nr_jited_ksyms = info->nr_jited_ksyms;
+ dd.jited_ksyms = (__u64 *) info->jited_ksyms;
dd.btf = btf;
dd.func_info = func_info;
- dd.finfo_rec_size = finfo_rec_size;
+ dd.finfo_rec_size = info->func_info_rec_size;
dd.prog_linfo = prog_linfo;
if (json_output)
- dump_xlated_json(&dd, buf, *member_len, opcodes,
+ dump_xlated_json(&dd, buf, member_len, opcodes,
linum);
else
- dump_xlated_plain(&dd, buf, *member_len, opcodes,
+ dump_xlated_plain(&dd, buf, member_len, opcodes,
linum);
kernel_syms_destroy(&dd);
}
- free(buf);
- free(func_ksyms);
- free(func_lens);
- free(func_info);
- free(linfo);
- free(jited_linfo);
- bpf_prog_linfo__free(prog_linfo);
+ free(info_linear);
return 0;
err_free:
- free(buf);
- free(func_ksyms);
- free(func_lens);
- free(func_info);
- free(linfo);
- free(jited_linfo);
- bpf_prog_linfo__free(prog_linfo);
+ free(info_linear);
return -1;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 04/11] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 03/11] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
` (4 subsequent siblings)
6 siblings, 0 replies; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
With bpf_program__get_prog_info_linear, we can simplify the logic that
synthesizes bpf events.
This patch doesn't change the behavior of the code.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/util/bpf-event.c | 118 ++++++++++++------------------------
1 file changed, 40 insertions(+), 78 deletions(-)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 796ef793f4ce..e6dfb95029e5 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -3,7 +3,9 @@
#include <stdlib.h>
#include <bpf/bpf.h>
#include <bpf/btf.h>
+#include <bpf/libbpf.h>
#include <linux/btf.h>
+#include <linux/err.h>
#include "bpf-event.h"
#include "debug.h"
#include "symbol.h"
@@ -49,99 +51,62 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
{
struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
struct bpf_event *bpf_event = &event->bpf_event;
- u32 sub_prog_cnt, i, func_info_rec_size = 0;
- u8 (*prog_tags)[BPF_TAG_SIZE] = NULL;
- struct bpf_prog_info info = { .type = 0, };
- u32 info_len = sizeof(info);
- void *func_infos = NULL;
- u64 *prog_addrs = NULL;
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_info *info;
struct btf *btf = NULL;
- u32 *prog_lens = NULL;
bool has_btf = false;
- char errbuf[512];
+ u32 sub_prog_cnt, i;
int err = 0;
+ u64 arrays;
- /* Call bpf_obj_get_info_by_fd() to get sizes of arrays */
- err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
+ 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;
- if (err) {
- pr_debug("%s: failed to get BPF program info: %s, aborting\n",
- __func__, str_error_r(errno, errbuf, sizeof(errbuf)));
+ info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+ if (IS_ERR_OR_NULL(info_linear)) {
+ info_linear = NULL;
+ pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
return -1;
}
- if (info_len < offsetof(struct bpf_prog_info, prog_tags)) {
+
+ if (info_linear->info_len < offsetof(struct bpf_prog_info, prog_tags)) {
pr_debug("%s: the kernel is too old, aborting\n", __func__);
return -2;
}
+ info = &info_linear->info;
+
/* number of ksyms, func_lengths, and tags should match */
- sub_prog_cnt = info.nr_jited_ksyms;
- if (sub_prog_cnt != info.nr_prog_tags ||
- sub_prog_cnt != info.nr_jited_func_lens)
+ sub_prog_cnt = info->nr_jited_ksyms;
+ if (sub_prog_cnt != info->nr_prog_tags ||
+ sub_prog_cnt != info->nr_jited_func_lens)
return -1;
/* check BTF func info support */
- if (info.btf_id && info.nr_func_info && info.func_info_rec_size) {
+ if (info->btf_id && info->nr_func_info && info->func_info_rec_size) {
/* btf func info number should be same as sub_prog_cnt */
- if (sub_prog_cnt != info.nr_func_info) {
+ if (sub_prog_cnt != info->nr_func_info) {
pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__);
- return -1;
- }
- if (btf__get_from_id(info.btf_id, &btf)) {
- pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info.btf_id);
- return -1;
+ err = -1;
+ goto out;
}
- func_info_rec_size = info.func_info_rec_size;
- func_infos = calloc(sub_prog_cnt, func_info_rec_size);
- if (!func_infos) {
- pr_debug("%s: failed to allocate memory for func_infos, aborting\n", __func__);
- return -1;
+ if (btf__get_from_id(info->btf_id, &btf)) {
+ pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info->btf_id);
+ err = -1;
+ btf = NULL;
+ goto out;
}
has_btf = true;
}
- /*
- * We need address, length, and tag for each sub program.
- * Allocate memory and call bpf_obj_get_info_by_fd() again
- */
- prog_addrs = calloc(sub_prog_cnt, sizeof(u64));
- if (!prog_addrs) {
- pr_debug("%s: failed to allocate memory for prog_addrs, aborting\n", __func__);
- goto out;
- }
- prog_lens = calloc(sub_prog_cnt, sizeof(u32));
- if (!prog_lens) {
- pr_debug("%s: failed to allocate memory for prog_lens, aborting\n", __func__);
- goto out;
- }
- prog_tags = calloc(sub_prog_cnt, BPF_TAG_SIZE);
- if (!prog_tags) {
- pr_debug("%s: failed to allocate memory for prog_tags, aborting\n", __func__);
- goto out;
- }
-
- memset(&info, 0, sizeof(info));
- info.nr_jited_ksyms = sub_prog_cnt;
- info.nr_jited_func_lens = sub_prog_cnt;
- info.nr_prog_tags = sub_prog_cnt;
- info.jited_ksyms = ptr_to_u64(prog_addrs);
- info.jited_func_lens = ptr_to_u64(prog_lens);
- info.prog_tags = ptr_to_u64(prog_tags);
- info_len = sizeof(info);
- if (has_btf) {
- info.nr_func_info = sub_prog_cnt;
- info.func_info_rec_size = func_info_rec_size;
- info.func_info = ptr_to_u64(func_infos);
- }
-
- err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
- if (err) {
- pr_debug("%s: failed to get BPF program info, aborting\n", __func__);
- goto out;
- }
-
/* Synthesize PERF_RECORD_KSYMBOL */
for (i = 0; i < sub_prog_cnt; i++) {
+ u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
+ __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
+ __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
+ void *func_infos = (void *)(info->func_info);
const struct bpf_func_info *finfo;
const char *short_name = NULL;
const struct btf_type *t;
@@ -163,13 +128,13 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
KSYM_NAME_LEN - name_len,
prog_tags[i], BPF_TAG_SIZE);
if (has_btf) {
- finfo = func_infos + i * info.func_info_rec_size;
+ finfo = func_infos + i * info->func_info_rec_size;
t = btf__type_by_id(btf, finfo->type_id);
short_name = btf__name_by_offset(btf, t->name_off);
} else if (i == 0 && sub_prog_cnt == 1) {
/* no subprog */
- if (info.name[0])
- short_name = info.name;
+ if (info->name[0])
+ short_name = info->name;
} else
short_name = "F";
if (short_name)
@@ -195,9 +160,9 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
},
.type = PERF_BPF_EVENT_PROG_LOAD,
.flags = 0,
- .id = info.id,
+ .id = info->id,
};
- memcpy(bpf_event->tag, prog_tags[i], BPF_TAG_SIZE);
+ memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
memset((void *)event + event->header.size, 0, machine->id_hdr_size);
event->header.size += machine->id_hdr_size;
err = perf_tool__process_synth_event(tool, event,
@@ -205,10 +170,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
}
out:
- free(prog_tags);
- free(prog_lens);
- free(prog_addrs);
- free(func_infos);
+ free(info_linear);
free(btf);
return err ? -1 : 0;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 03/11] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 04/11] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 14:21 ` Arnaldo Carvalho de Melo
2019-02-15 0:00 ` [PATCH v2 perf,bpf 06/11] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
` (3 subsequent siblings)
6 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
bpf_prog_info contains information necessary to annotate bpf programs.
This patch saves bpf_prog_info for bpf programs loaded in the system.
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 | 39 +++++++++++++----
tools/perf/util/bpf-event.h | 15 +++++--
tools/perf/util/env.c | 83 +++++++++++++++++++++++++++++++++++++
tools/perf/util/env.h | 14 +++++++
6 files changed, 142 insertions(+), 13 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 88ea11d57c6f..2355e0a9eda0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1083,7 +1083,7 @@ static int record__synthesize(struct record *rec, bool tail)
return err;
}
- err = perf_event__synthesize_bpf_events(tool, process_synthesized_event,
+ err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
machine, opts);
if (err < 0)
pr_warning("Couldn't synthesize bpf events.\n");
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5a486d4de56e..27d8d42e0a4d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1216,7 +1216,7 @@ static int __cmd_top(struct perf_top *top)
init_process_thread(top);
- ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process,
+ ret = perf_event__synthesize_bpf_events(top->session, perf_event__process,
&top->session->machines.host,
&top->record_opts);
if (ret < 0)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index e6dfb95029e5..ead599bc4f4e 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -1,15 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdlib.h>
-#include <bpf/bpf.h>
-#include <bpf/btf.h>
-#include <bpf/libbpf.h>
-#include <linux/btf.h>
#include <linux/err.h>
#include "bpf-event.h"
#include "debug.h"
#include "symbol.h"
#include "machine.h"
+#include "env.h"
+#include "session.h"
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
@@ -42,7 +40,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
* -1 for failures;
* -2 for lack of kernel support.
*/
-static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
+static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
perf_event__handler_t process,
struct machine *machine,
int fd,
@@ -52,17 +50,29 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
struct bpf_event *bpf_event = &event->bpf_event;
struct bpf_prog_info_linear *info_linear;
+ struct perf_tool *tool = session->tool;
+ struct bpf_prog_info_node *info_node;
struct bpf_prog_info *info;
struct btf *btf = NULL;
bool has_btf = false;
+ struct perf_env *env;
u32 sub_prog_cnt, i;
int err = 0;
u64 arrays;
+ /*
+ * for perf-record and perf-report use header.env;
+ * otherwise, use global perf_env.
+ */
+ env = session->data ? &session->header.env : &perf_env;
+
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)) {
@@ -151,8 +161,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
machine, process);
}
- /* Synthesize PERF_RECORD_BPF_EVENT */
if (opts->bpf_event) {
+ /* Synthesize PERF_RECORD_BPF_EVENT */
*bpf_event = (struct bpf_event){
.header = {
.type = PERF_RECORD_BPF_EVENT,
@@ -165,6 +175,19 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
memset((void *)event + event->header.size, 0, machine->id_hdr_size);
event->header.size += machine->id_hdr_size;
+
+ /* save bpf_prog_info to env */
+ 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);
+ info_linear = NULL;
+ }
+
+ /*
+ * process after saving bpf_prog_info to env, so that
+ * required information is ready for look up
+ */
err = perf_tool__process_synth_event(tool, event,
machine, process);
}
@@ -175,7 +198,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
return err ? -1 : 0;
}
-int perf_event__synthesize_bpf_events(struct perf_tool *tool,
+int perf_event__synthesize_bpf_events(struct perf_session *session,
perf_event__handler_t process,
struct machine *machine,
struct record_opts *opts)
@@ -209,7 +232,7 @@ int perf_event__synthesize_bpf_events(struct perf_tool *tool,
continue;
}
- err = perf_event__synthesize_one_bpf_prog(tool, process,
+ err = perf_event__synthesize_one_bpf_prog(session, process,
machine, fd,
event, opts);
close(fd);
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 7890067e1a37..11e6730b6105 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,19 +3,28 @@
#define __PERF_BPF_EVENT_H
#include <linux/compiler.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
+#include <linux/rbtree.h>
#include "event.h"
struct machine;
union perf_event;
struct perf_sample;
-struct perf_tool;
struct record_opts;
+struct bpf_prog_info_node {
+ struct bpf_prog_info_linear *info_linear;
+ struct rb_node rb_node;
+};
+
#ifdef HAVE_LIBBPF_SUPPORT
int machine__process_bpf_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
-int perf_event__synthesize_bpf_events(struct perf_tool *tool,
+int perf_event__synthesize_bpf_events(struct perf_session *session,
perf_event__handler_t process,
struct machine *machine,
struct record_opts *opts);
@@ -27,7 +36,7 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu
return 0;
}
-static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused,
+static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused,
perf_event__handler_t process __maybe_unused,
struct machine *machine __maybe_unused,
struct record_opts *opts __maybe_unused)
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..665b6fe3c7b2 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -8,10 +8,86 @@
struct perf_env perf_env;
+void perf_env__insert_bpf_prog_info(struct perf_env *env,
+ struct bpf_prog_info_node *info_node)
+{
+ __u32 prog_id = info_node->info_linear->info.id;
+ struct bpf_prog_info_node *node;
+ struct rb_node *parent = NULL;
+ struct rb_node **p;
+
+ down_write(&env->bpf_info_lock);
+ p = &env->bpf_prog_infos.rb_node;
+
+ while (*p != NULL) {
+ parent = *p;
+ node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
+ if (prog_id < node->info_linear->info.id) {
+ p = &(*p)->rb_left;
+ } else if (prog_id > node->info_linear->info.id) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_debug("duplicated bpf prog info %u\n", prog_id);
+ up_write(&env->bpf_info_lock);
+ return;
+ }
+ }
+
+ rb_link_node(&info_node->rb_node, parent, p);
+ rb_insert_color(&info_node->rb_node, &env->bpf_prog_infos);
+ up_write(&env->bpf_info_lock);
+}
+
+struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
+ __u32 prog_id)
+{
+ struct bpf_prog_info_node *node = NULL;
+ struct rb_node *n;
+
+ down_read(&env->bpf_info_lock);
+ n = env->bpf_prog_infos.rb_node;
+
+ while (n) {
+ node = rb_entry(n, struct bpf_prog_info_node, rb_node);
+ if (prog_id < node->info_linear->info.id)
+ n = n->rb_left;
+ else if (prog_id > node->info_linear->info.id)
+ n = n->rb_right;
+ else
+ break;
+ }
+
+ up_read(&env->bpf_info_lock);
+ return node;
+}
+
+/* purge data in bpf_prog_infos tree */
+static void purge_bpf_info(struct perf_env *env)
+{
+ struct rb_root *root;
+ struct rb_node *next;
+
+ down_write(&env->bpf_info_lock);
+
+ root = &env->bpf_prog_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);
+ rb_erase_init(&node->rb_node, root);
+ free(node);
+ }
+ up_write(&env->bpf_info_lock);
+}
+
void perf_env__exit(struct perf_env *env)
{
int i;
+ purge_bpf_info(env);
zfree(&env->hostname);
zfree(&env->os_release);
zfree(&env->version);
@@ -38,6 +114,12 @@ void perf_env__exit(struct perf_env *env)
zfree(&env->memory_nodes);
}
+static void init_bpf_rb_trees(struct perf_env *env)
+{
+ env->bpf_prog_infos = RB_ROOT;
+ init_rwsem(&env->bpf_info_lock);
+}
+
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
{
int i;
@@ -59,6 +141,7 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
env->nr_cmdline = argc;
+ init_bpf_rb_trees(env);
return 0;
out_free:
zfree(&env->cmdline_argv);
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..a6d25e91bc98 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,10 @@
#define __PERF_ENV_H
#include <linux/types.h>
+#include <linux/rbtree.h>
#include "cpumap.h"
+#include "rwsem.h"
+#include "bpf-event.h"
struct cpu_topology_map {
int socket_id;
@@ -64,6 +67,13 @@ struct perf_env {
struct memory_node *memory_nodes;
unsigned long long memory_bsize;
u64 clockid_res_ns;
+
+ /*
+ * bpf_info_lock protects bpf rbtrees. This is needed because the
+ * trees are accessed by different threads in perf-top
+ */
+ struct rw_semaphore bpf_info_lock;
+ struct rb_root bpf_prog_infos;
};
extern struct perf_env perf_env;
@@ -80,4 +90,8 @@ const char *perf_env__arch(struct perf_env *env);
const char *perf_env__raw_arch(struct perf_env *env);
int perf_env__nr_cpus_avail(struct perf_env *env);
+void perf_env__insert_bpf_prog_info(struct perf_env *env,
+ struct bpf_prog_info_node *info_node);
+struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
+ __u32 prog_id);
#endif /* __PERF_ENV_H */
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env
2019-02-15 0:00 ` [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
@ 2019-02-15 14:21 ` Arnaldo Carvalho de Melo
2019-02-15 17:04 ` Song Liu
0 siblings, 1 reply; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 14:21 UTC (permalink / raw)
To: Song Liu
Cc: netdev, linux-kernel, ast, daniel, kernel-team, peterz, jolsa, namhyung
Em Thu, Feb 14, 2019 at 04:00:06PM -0800, Song Liu escreveu:
> bpf_prog_info contains information necessary to annotate bpf programs.
> This patch saves bpf_prog_info for bpf programs loaded in the system.
>
> 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 | 39 +++++++++++++----
> tools/perf/util/bpf-event.h | 15 +++++--
> tools/perf/util/env.c | 83 +++++++++++++++++++++++++++++++++++++
> tools/perf/util/env.h | 14 +++++++
> 6 files changed, 142 insertions(+), 13 deletions(-)
>
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 88ea11d57c6f..2355e0a9eda0 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -1083,7 +1083,7 @@ static int record__synthesize(struct record *rec, bool tail)
> return err;
> }
>
> - err = perf_event__synthesize_bpf_events(tool, process_synthesized_event,
> + err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
> machine, opts);
> if (err < 0)
> pr_warning("Couldn't synthesize bpf events.\n");
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 5a486d4de56e..27d8d42e0a4d 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -1216,7 +1216,7 @@ static int __cmd_top(struct perf_top *top)
>
> init_process_thread(top);
>
> - ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process,
> + ret = perf_event__synthesize_bpf_events(top->session, perf_event__process,
> &top->session->machines.host,
> &top->record_opts);
> if (ret < 0)
> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> index e6dfb95029e5..ead599bc4f4e 100644
> --- a/tools/perf/util/bpf-event.c
> +++ b/tools/perf/util/bpf-event.c
> @@ -1,15 +1,13 @@
> // SPDX-License-Identifier: GPL-2.0
> #include <errno.h>
> #include <stdlib.h>
> -#include <bpf/bpf.h>
> -#include <bpf/btf.h>
> -#include <bpf/libbpf.h>
> -#include <linux/btf.h>
I think you need these here, since in this C file you will use the
definitions for these structs, see further comments below.
> #include <linux/err.h>
> #include "bpf-event.h"
> #include "debug.h"
> #include "symbol.h"
> #include "machine.h"
> +#include "env.h"
> +#include "session.h"
>
> #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
>
> @@ -42,7 +40,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
> * -1 for failures;
> * -2 for lack of kernel support.
> */
> -static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
> +static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
> perf_event__handler_t process,
> struct machine *machine,
> int fd,
> @@ -52,17 +50,29 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
> struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
> struct bpf_event *bpf_event = &event->bpf_event;
> struct bpf_prog_info_linear *info_linear;
> + struct perf_tool *tool = session->tool;
> + struct bpf_prog_info_node *info_node;
> struct bpf_prog_info *info;
> struct btf *btf = NULL;
> bool has_btf = false;
> + struct perf_env *env;
> u32 sub_prog_cnt, i;
> int err = 0;
> u64 arrays;
>
> + /*
> + * for perf-record and perf-report use header.env;
> + * otherwise, use global perf_env.
> + */
> + env = session->data ? &session->header.env : &perf_env;
> +
> 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)) {
> @@ -151,8 +161,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
> machine, process);
> }
>
> - /* Synthesize PERF_RECORD_BPF_EVENT */
> if (opts->bpf_event) {
> + /* Synthesize PERF_RECORD_BPF_EVENT */
> *bpf_event = (struct bpf_event){
> .header = {
> .type = PERF_RECORD_BPF_EVENT,
> @@ -165,6 +175,19 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
> memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
> memset((void *)event + event->header.size, 0, machine->id_hdr_size);
> event->header.size += machine->id_hdr_size;
> +
> + /* save bpf_prog_info to env */
> + 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);
> + info_linear = NULL;
> + }
> +
> + /*
> + * process after saving bpf_prog_info to env, so that
> + * required information is ready for look up
> + */
> err = perf_tool__process_synth_event(tool, event,
> machine, process);
> }
> @@ -175,7 +198,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
> return err ? -1 : 0;
> }
>
> -int perf_event__synthesize_bpf_events(struct perf_tool *tool,
> +int perf_event__synthesize_bpf_events(struct perf_session *session,
> perf_event__handler_t process,
> struct machine *machine,
> struct record_opts *opts)
> @@ -209,7 +232,7 @@ int perf_event__synthesize_bpf_events(struct perf_tool *tool,
> continue;
> }
>
> - err = perf_event__synthesize_one_bpf_prog(tool, process,
> + err = perf_event__synthesize_one_bpf_prog(session, process,
> machine, fd,
> event, opts);
> close(fd);
> diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
> index 7890067e1a37..11e6730b6105 100644
> --- a/tools/perf/util/bpf-event.h
> +++ b/tools/perf/util/bpf-event.h
> @@ -3,19 +3,28 @@
> #define __PERF_BPF_EVENT_H
>
> #include <linux/compiler.h>
> +#include <bpf/bpf.h>
> +#include <bpf/btf.h>
> +#include <bpf/libbpf.h>
> +#include <linux/btf.h>
Are you sure you'll need all of these headers here? Perhaps just some
forward declarations will do?
In fact the only bpf or btf structure here seems to be
bpf_prog_info_linear, which needs ust a forward declaration.
Avoiding these includes reduces the build time, and since the build-test
target does many builds and I want to build this in many containers, we
should try to reduce the build time by using just what is needed in each
header and C file. Also during development it helps with not rebuilding
tons of things when something unrelated changes in a header, etc.
- Arnaldo
> +#include <linux/rbtree.h>
> #include "event.h"
>
> struct machine;
> union perf_event;
> struct perf_sample;
> -struct perf_tool;
> struct record_opts;
>
> +struct bpf_prog_info_node {
> + struct bpf_prog_info_linear *info_linear;
> + struct rb_node rb_node;
> +};
> +
> #ifdef HAVE_LIBBPF_SUPPORT
> int machine__process_bpf_event(struct machine *machine, union perf_event *event,
> struct perf_sample *sample);
>
> -int perf_event__synthesize_bpf_events(struct perf_tool *tool,
> +int perf_event__synthesize_bpf_events(struct perf_session *session,
> perf_event__handler_t process,
> struct machine *machine,
> struct record_opts *opts);
> @@ -27,7 +36,7 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu
> return 0;
> }
>
> -static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused,
> +static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused,
> perf_event__handler_t process __maybe_unused,
> struct machine *machine __maybe_unused,
> struct record_opts *opts __maybe_unused)
> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
> index 4c23779e271a..665b6fe3c7b2 100644
> --- a/tools/perf/util/env.c
> +++ b/tools/perf/util/env.c
> @@ -8,10 +8,86 @@
>
> struct perf_env perf_env;
>
> +void perf_env__insert_bpf_prog_info(struct perf_env *env,
> + struct bpf_prog_info_node *info_node)
> +{
> + __u32 prog_id = info_node->info_linear->info.id;
> + struct bpf_prog_info_node *node;
> + struct rb_node *parent = NULL;
> + struct rb_node **p;
> +
> + down_write(&env->bpf_info_lock);
> + p = &env->bpf_prog_infos.rb_node;
> +
> + while (*p != NULL) {
> + parent = *p;
> + node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
> + if (prog_id < node->info_linear->info.id) {
> + p = &(*p)->rb_left;
> + } else if (prog_id > node->info_linear->info.id) {
> + p = &(*p)->rb_right;
> + } else {
> + pr_debug("duplicated bpf prog info %u\n", prog_id);
> + up_write(&env->bpf_info_lock);
> + return;
> + }
> + }
> +
> + rb_link_node(&info_node->rb_node, parent, p);
> + rb_insert_color(&info_node->rb_node, &env->bpf_prog_infos);
> + up_write(&env->bpf_info_lock);
> +}
> +
> +struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
> + __u32 prog_id)
> +{
> + struct bpf_prog_info_node *node = NULL;
> + struct rb_node *n;
> +
> + down_read(&env->bpf_info_lock);
> + n = env->bpf_prog_infos.rb_node;
> +
> + while (n) {
> + node = rb_entry(n, struct bpf_prog_info_node, rb_node);
> + if (prog_id < node->info_linear->info.id)
> + n = n->rb_left;
> + else if (prog_id > node->info_linear->info.id)
> + n = n->rb_right;
> + else
> + break;
> + }
> +
> + up_read(&env->bpf_info_lock);
> + return node;
> +}
> +
> +/* purge data in bpf_prog_infos tree */
> +static void purge_bpf_info(struct perf_env *env)
> +{
> + struct rb_root *root;
> + struct rb_node *next;
> +
> + down_write(&env->bpf_info_lock);
> +
> + root = &env->bpf_prog_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);
> + rb_erase_init(&node->rb_node, root);
> + free(node);
> + }
> + up_write(&env->bpf_info_lock);
> +}
> +
> void perf_env__exit(struct perf_env *env)
> {
> int i;
>
> + purge_bpf_info(env);
> zfree(&env->hostname);
> zfree(&env->os_release);
> zfree(&env->version);
> @@ -38,6 +114,12 @@ void perf_env__exit(struct perf_env *env)
> zfree(&env->memory_nodes);
> }
>
> +static void init_bpf_rb_trees(struct perf_env *env)
> +{
> + env->bpf_prog_infos = RB_ROOT;
> + init_rwsem(&env->bpf_info_lock);
> +}
> +
> int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
> {
> int i;
> @@ -59,6 +141,7 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
>
> env->nr_cmdline = argc;
>
> + init_bpf_rb_trees(env);
> return 0;
> out_free:
> zfree(&env->cmdline_argv);
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index d01b8355f4ca..a6d25e91bc98 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -3,7 +3,10 @@
> #define __PERF_ENV_H
>
> #include <linux/types.h>
> +#include <linux/rbtree.h>
> #include "cpumap.h"
> +#include "rwsem.h"
You don't need the following header, just use a forward declaration for
the sole struct you use with a pointer:
struct bpf_prog_info_node;
> +#include "bpf-event.h"
>
> struct cpu_topology_map {
> int socket_id;
> @@ -64,6 +67,13 @@ struct perf_env {
> struct memory_node *memory_nodes;
> unsigned long long memory_bsize;
> u64 clockid_res_ns;
> +
> + /*
> + * bpf_info_lock protects bpf rbtrees. This is needed because the
> + * trees are accessed by different threads in perf-top
> + */
> + struct rw_semaphore bpf_info_lock;
> + struct rb_root bpf_prog_infos;
Please group this into a structure, i.e.:
struct {
struct rw_semaphore lock;
struct rb_root infos;
} bpf_progs;
> };
>
> extern struct perf_env perf_env;
> @@ -80,4 +90,8 @@ const char *perf_env__arch(struct perf_env *env);
> const char *perf_env__raw_arch(struct perf_env *env);
> int perf_env__nr_cpus_avail(struct perf_env *env);
>
> +void perf_env__insert_bpf_prog_info(struct perf_env *env,
> + struct bpf_prog_info_node *info_node);
> +struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
> + __u32 prog_id);
> #endif /* __PERF_ENV_H */
> --
> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env
2019-02-15 14:21 ` Arnaldo Carvalho de Melo
@ 2019-02-15 17:04 ` Song Liu
0 siblings, 0 replies; 31+ messages in thread
From: Song Liu @ 2019-02-15 17:04 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Netdev, linux-kernel, ast, daniel, Kernel Team, peterz, jolsa, namhyung
> On Feb 15, 2019, at 6:21 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
>
> Em Thu, Feb 14, 2019 at 04:00:06PM -0800, Song Liu escreveu:
>> bpf_prog_info contains information necessary to annotate bpf programs.
>> This patch saves bpf_prog_info for bpf programs loaded in the system.
>>
>> 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 | 39 +++++++++++++----
>> tools/perf/util/bpf-event.h | 15 +++++--
>> tools/perf/util/env.c | 83 +++++++++++++++++++++++++++++++++++++
>> tools/perf/util/env.h | 14 +++++++
>> 6 files changed, 142 insertions(+), 13 deletions(-)
>>
>> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
>> index 88ea11d57c6f..2355e0a9eda0 100644
>> --- a/tools/perf/builtin-record.c
>> +++ b/tools/perf/builtin-record.c
>> @@ -1083,7 +1083,7 @@ static int record__synthesize(struct record *rec, bool tail)
>> return err;
>> }
>>
>> - err = perf_event__synthesize_bpf_events(tool, process_synthesized_event,
>> + err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
>> machine, opts);
>> if (err < 0)
>> pr_warning("Couldn't synthesize bpf events.\n");
>> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
>> index 5a486d4de56e..27d8d42e0a4d 100644
>> --- a/tools/perf/builtin-top.c
>> +++ b/tools/perf/builtin-top.c
>> @@ -1216,7 +1216,7 @@ static int __cmd_top(struct perf_top *top)
>>
>> init_process_thread(top);
>>
>> - ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process,
>> + ret = perf_event__synthesize_bpf_events(top->session, perf_event__process,
>> &top->session->machines.host,
>> &top->record_opts);
>> if (ret < 0)
>> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
>> index e6dfb95029e5..ead599bc4f4e 100644
>> --- a/tools/perf/util/bpf-event.c
>> +++ b/tools/perf/util/bpf-event.c
>> @@ -1,15 +1,13 @@
>> // SPDX-License-Identifier: GPL-2.0
>> #include <errno.h>
>> #include <stdlib.h>
>> -#include <bpf/bpf.h>
>> -#include <bpf/btf.h>
>> -#include <bpf/libbpf.h>
>> -#include <linux/btf.h>
>
> I think you need these here, since in this C file you will use the
> definitions for these structs, see further comments below.
>
>> #include <linux/err.h>
>> #include "bpf-event.h"
>> #include "debug.h"
>> #include "symbol.h"
>> #include "machine.h"
>> +#include "env.h"
>> +#include "session.h"
>>
>> #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
>>
>> @@ -42,7 +40,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
>> * -1 for failures;
>> * -2 for lack of kernel support.
>> */
>> -static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
>> +static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
>> perf_event__handler_t process,
>> struct machine *machine,
>> int fd,
>> @@ -52,17 +50,29 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
>> struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
>> struct bpf_event *bpf_event = &event->bpf_event;
>> struct bpf_prog_info_linear *info_linear;
>> + struct perf_tool *tool = session->tool;
>> + struct bpf_prog_info_node *info_node;
>> struct bpf_prog_info *info;
>> struct btf *btf = NULL;
>> bool has_btf = false;
>> + struct perf_env *env;
>> u32 sub_prog_cnt, i;
>> int err = 0;
>> u64 arrays;
>>
>> + /*
>> + * for perf-record and perf-report use header.env;
>> + * otherwise, use global perf_env.
>> + */
>> + env = session->data ? &session->header.env : &perf_env;
>> +
>> 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)) {
>> @@ -151,8 +161,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
>> machine, process);
>> }
>>
>> - /* Synthesize PERF_RECORD_BPF_EVENT */
>> if (opts->bpf_event) {
>> + /* Synthesize PERF_RECORD_BPF_EVENT */
>> *bpf_event = (struct bpf_event){
>> .header = {
>> .type = PERF_RECORD_BPF_EVENT,
>> @@ -165,6 +175,19 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
>> memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
>> memset((void *)event + event->header.size, 0, machine->id_hdr_size);
>> event->header.size += machine->id_hdr_size;
>> +
>> + /* save bpf_prog_info to env */
>> + 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);
>> + info_linear = NULL;
>> + }
>> +
>> + /*
>> + * process after saving bpf_prog_info to env, so that
>> + * required information is ready for look up
>> + */
>> err = perf_tool__process_synth_event(tool, event,
>> machine, process);
>> }
>> @@ -175,7 +198,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
>> return err ? -1 : 0;
>> }
>>
>> -int perf_event__synthesize_bpf_events(struct perf_tool *tool,
>> +int perf_event__synthesize_bpf_events(struct perf_session *session,
>> perf_event__handler_t process,
>> struct machine *machine,
>> struct record_opts *opts)
>> @@ -209,7 +232,7 @@ int perf_event__synthesize_bpf_events(struct perf_tool *tool,
>> continue;
>> }
>>
>> - err = perf_event__synthesize_one_bpf_prog(tool, process,
>> + err = perf_event__synthesize_one_bpf_prog(session, process,
>> machine, fd,
>> event, opts);
>> close(fd);
>> diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
>> index 7890067e1a37..11e6730b6105 100644
>> --- a/tools/perf/util/bpf-event.h
>> +++ b/tools/perf/util/bpf-event.h
>> @@ -3,19 +3,28 @@
>> #define __PERF_BPF_EVENT_H
>>
>> #include <linux/compiler.h>
>> +#include <bpf/bpf.h>
>> +#include <bpf/btf.h>
>> +#include <bpf/libbpf.h>
>> +#include <linux/btf.h>
>
> Are you sure you'll need all of these headers here? Perhaps just some
> forward declarations will do?
>
> In fact the only bpf or btf structure here seems to be
> bpf_prog_info_linear, which needs ust a forward declaration.
>
> Avoiding these includes reduces the build time, and since the build-test
> target does many builds and I want to build this in many containers, we
> should try to reduce the build time by using just what is needed in each
> header and C file. Also during development it helps with not rebuilding
> tons of things when something unrelated changes in a header, etc.
I see. I will fix this in next version.
>
> - Arnaldo
>
>> +#include <linux/rbtree.h>
>> #include "event.h"
>>
>> struct machine;
>> union perf_event;
>> struct perf_sample;
>> -struct perf_tool;
>> struct record_opts;
>>
>> +struct bpf_prog_info_node {
>> + struct bpf_prog_info_linear *info_linear;
>> + struct rb_node rb_node;
>> +};
>> +
>> #ifdef HAVE_LIBBPF_SUPPORT
>> int machine__process_bpf_event(struct machine *machine, union perf_event *event,
>> struct perf_sample *sample);
>>
>> -int perf_event__synthesize_bpf_events(struct perf_tool *tool,
>> +int perf_event__synthesize_bpf_events(struct perf_session *session,
>> perf_event__handler_t process,
>> struct machine *machine,
>> struct record_opts *opts);
>> @@ -27,7 +36,7 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu
>> return 0;
>> }
>>
>> -static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused,
>> +static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused,
>> perf_event__handler_t process __maybe_unused,
>> struct machine *machine __maybe_unused,
>> struct record_opts *opts __maybe_unused)
>> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
>> index 4c23779e271a..665b6fe3c7b2 100644
>> --- a/tools/perf/util/env.c
>> +++ b/tools/perf/util/env.c
>> @@ -8,10 +8,86 @@
>>
>> struct perf_env perf_env;
>>
>> +void perf_env__insert_bpf_prog_info(struct perf_env *env,
>> + struct bpf_prog_info_node *info_node)
>> +{
>> + __u32 prog_id = info_node->info_linear->info.id;
>> + struct bpf_prog_info_node *node;
>> + struct rb_node *parent = NULL;
>> + struct rb_node **p;
>> +
>> + down_write(&env->bpf_info_lock);
>> + p = &env->bpf_prog_infos.rb_node;
>> +
>> + while (*p != NULL) {
>> + parent = *p;
>> + node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
>> + if (prog_id < node->info_linear->info.id) {
>> + p = &(*p)->rb_left;
>> + } else if (prog_id > node->info_linear->info.id) {
>> + p = &(*p)->rb_right;
>> + } else {
>> + pr_debug("duplicated bpf prog info %u\n", prog_id);
>> + up_write(&env->bpf_info_lock);
>> + return;
>> + }
>> + }
>> +
>> + rb_link_node(&info_node->rb_node, parent, p);
>> + rb_insert_color(&info_node->rb_node, &env->bpf_prog_infos);
>> + up_write(&env->bpf_info_lock);
>> +}
>> +
>> +struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
>> + __u32 prog_id)
>> +{
>> + struct bpf_prog_info_node *node = NULL;
>> + struct rb_node *n;
>> +
>> + down_read(&env->bpf_info_lock);
>> + n = env->bpf_prog_infos.rb_node;
>> +
>> + while (n) {
>> + node = rb_entry(n, struct bpf_prog_info_node, rb_node);
>> + if (prog_id < node->info_linear->info.id)
>> + n = n->rb_left;
>> + else if (prog_id > node->info_linear->info.id)
>> + n = n->rb_right;
>> + else
>> + break;
>> + }
>> +
>> + up_read(&env->bpf_info_lock);
>> + return node;
>> +}
>> +
>> +/* purge data in bpf_prog_infos tree */
>> +static void purge_bpf_info(struct perf_env *env)
>> +{
>> + struct rb_root *root;
>> + struct rb_node *next;
>> +
>> + down_write(&env->bpf_info_lock);
>> +
>> + root = &env->bpf_prog_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);
>> + rb_erase_init(&node->rb_node, root);
>> + free(node);
>> + }
>> + up_write(&env->bpf_info_lock);
>> +}
>> +
>> void perf_env__exit(struct perf_env *env)
>> {
>> int i;
>>
>> + purge_bpf_info(env);
>> zfree(&env->hostname);
>> zfree(&env->os_release);
>> zfree(&env->version);
>> @@ -38,6 +114,12 @@ void perf_env__exit(struct perf_env *env)
>> zfree(&env->memory_nodes);
>> }
>>
>> +static void init_bpf_rb_trees(struct perf_env *env)
>> +{
>> + env->bpf_prog_infos = RB_ROOT;
>> + init_rwsem(&env->bpf_info_lock);
>> +}
>> +
>> int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
>> {
>> int i;
>> @@ -59,6 +141,7 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
>>
>> env->nr_cmdline = argc;
>>
>> + init_bpf_rb_trees(env);
>> return 0;
>> out_free:
>> zfree(&env->cmdline_argv);
>> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
>> index d01b8355f4ca..a6d25e91bc98 100644
>> --- a/tools/perf/util/env.h
>> +++ b/tools/perf/util/env.h
>> @@ -3,7 +3,10 @@
>> #define __PERF_ENV_H
>>
>> #include <linux/types.h>
>> +#include <linux/rbtree.h>
>> #include "cpumap.h"
>> +#include "rwsem.h"
>
> You don't need the following header, just use a forward declaration for
> the sole struct you use with a pointer:
>
> struct bpf_prog_info_node;
>
>> +#include "bpf-event.h"
>>
>> struct cpu_topology_map {
>> int socket_id;
>> @@ -64,6 +67,13 @@ struct perf_env {
>> struct memory_node *memory_nodes;
>> unsigned long long memory_bsize;
>> u64 clockid_res_ns;
>> +
>> + /*
>> + * bpf_info_lock protects bpf rbtrees. This is needed because the
>> + * trees are accessed by different threads in perf-top
>> + */
>> + struct rw_semaphore bpf_info_lock;
>> + struct rb_root bpf_prog_infos;
>
> Please group this into a structure, i.e.:
>
> struct {
> struct rw_semaphore lock;
> struct rb_root infos;
> } bpf_progs;
Will fix this in next version.
>
>> };
>>
>> extern struct perf_env perf_env;
>> @@ -80,4 +90,8 @@ const char *perf_env__arch(struct perf_env *env);
>> const char *perf_env__raw_arch(struct perf_env *env);
>> int perf_env__nr_cpus_avail(struct perf_env *env);
>>
>> +void perf_env__insert_bpf_prog_info(struct perf_env *env,
>> + struct bpf_prog_info_node *info_node);
>> +struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
>> + __u32 prog_id);
>> #endif /* __PERF_ENV_H */
>> --
>> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 06/11] perf, bpf: save bpf_prog_info information as headers to perf.data
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
` (2 preceding siblings ...)
2019-02-15 0:00 ` [PATCH v2 perf,bpf 05/11] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 07/11] perf, bpf: save btf in a rbtree in perf_env Song Liu
` (2 subsequent siblings)
6 siblings, 0 replies; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
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>
---
| 134 ++++++++++++++++++++++++++++++++++++++-
| 1 +
2 files changed, 134 insertions(+), 1 deletion(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index dec6d218c31c..2ae76a9d06f6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1080,6 +1080,51 @@ 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;
+ u32 count = 0;
+ int ret;
+
+ down_read(&env->bpf_info_lock);
+
+ root = &env->bpf_prog_infos;
+ next = rb_first(root);
+ while (next) {
+ ++count;
+ next = rb_next(next);
+ }
+
+ ret = do_write(ff, &count, sizeof(count));
+
+ if (ret < 0)
+ goto out;
+
+ 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);
+ bpf_program__bpil_offs_to_addr(node->info_linear);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ up_read(&env->bpf_info_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;
@@ -1560,6 +1605,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_info_lock);
+
+ root = &env->bpf_prog_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_info_lock);
+}
+
static void free_event_desc(struct perf_evsel *events)
{
struct perf_evsel *evsel;
@@ -2592,6 +2660,69 @@ 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 (do_read_u32(ff, &count))
+ return -1;
+
+ down_write(&env->bpf_info_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_info_lock);
+ return err;
+}
+
struct feature_ops {
int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2651,7 +2782,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 {
--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
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 07/11] perf, bpf: save btf in a rbtree in perf_env
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
` (3 preceding siblings ...)
2019-02-15 0:00 ` [PATCH v2 perf,bpf 06/11] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 14:30 ` Arnaldo Carvalho de Melo
2019-02-15 0:00 ` [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data Song Liu
2019-02-15 0:00 ` [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event Song Liu
6 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
btf contains information necessary to annotate bpf programs. This patch
saves btf for bpf programs loaded in the system.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/util/bpf-event.c | 22 +++++++++++++
tools/perf/util/bpf-event.h | 7 ++++
tools/perf/util/env.c | 65 +++++++++++++++++++++++++++++++++++++
tools/perf/util/env.h | 3 ++
4 files changed, 97 insertions(+)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index ead599bc4f4e..37a5b8134e00 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -30,6 +30,27 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
return 0;
}
+static int perf_fetch_btf(struct perf_env *env, u32 btf_id, struct btf *btf)
+{
+ struct btf_node *node;
+ u32 data_size;
+ const void *data;
+
+ data = btf__get_raw_data(btf, &data_size);
+
+ node = malloc(data_size + sizeof(struct btf_node));
+
+ if (!node)
+ return -1;
+
+ node->id = btf_id;
+ node->data_size = data_size;
+ memcpy(node->data, data, data_size);
+
+ perf_env__insert_btf(env, node);
+ return 0;
+}
+
/*
* Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
* program. One PERF_RECORD_BPF_EVENT is generated for the program. And
@@ -109,6 +130,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
goto out;
}
has_btf = true;
+ perf_fetch_btf(env, info->btf_id, btf);
}
/* Synthesize PERF_RECORD_KSYMBOL */
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 11e6730b6105..60ce24e4e5c6 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -20,6 +20,13 @@ struct bpf_prog_info_node {
struct rb_node rb_node;
};
+struct btf_node {
+ struct rb_node rb_node;
+ u32 id;
+ u32 data_size;
+ char data[];
+};
+
#ifdef HAVE_LIBBPF_SUPPORT
int machine__process_bpf_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 665b6fe3c7b2..6f9e3d4b94bc 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -61,6 +61,57 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
return node;
}
+void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
+{
+ struct rb_node *parent = NULL;
+ __u32 btf_id = btf_node->id;
+ struct btf_node *node;
+ struct rb_node **p;
+
+ down_write(&env->bpf_info_lock);
+ p = &env->btfs.rb_node;
+
+ while (*p != NULL) {
+ parent = *p;
+ node = rb_entry(parent, struct btf_node, rb_node);
+ if (btf_id < node->id) {
+ p = &(*p)->rb_left;
+ } else if (btf_id > node->id) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_debug("duplicated btf %u\n", btf_id);
+ up_write(&env->bpf_info_lock);
+ return;
+ }
+ }
+
+ rb_link_node(&btf_node->rb_node, parent, p);
+ rb_insert_color(&btf_node->rb_node, &env->btfs);
+ up_write(&env->bpf_info_lock);
+}
+
+struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
+{
+ struct btf_node *node = NULL;
+ struct rb_node *n;
+
+ down_read(&env->bpf_info_lock);
+ n = env->btfs.rb_node;
+
+ while (n) {
+ node = rb_entry(n, struct btf_node, rb_node);
+ if (btf_id < node->id)
+ n = n->rb_left;
+ else if (btf_id > node->id)
+ n = n->rb_right;
+ else
+ break;
+ }
+
+ up_read(&env->bpf_info_lock);
+ return node;
+}
+
/* purge data in bpf_prog_infos tree */
static void purge_bpf_info(struct perf_env *env)
{
@@ -80,6 +131,19 @@ static void purge_bpf_info(struct perf_env *env)
rb_erase_init(&node->rb_node, root);
free(node);
}
+
+ root = &env->btfs;
+ next = rb_first(root);
+
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ rb_erase_init(&node->rb_node, root);
+ free(node);
+ }
+
up_write(&env->bpf_info_lock);
}
@@ -117,6 +181,7 @@ void perf_env__exit(struct perf_env *env)
static void init_bpf_rb_trees(struct perf_env *env)
{
env->bpf_prog_infos = RB_ROOT;
+ env->btfs = RB_ROOT;
init_rwsem(&env->bpf_info_lock);
}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index a6d25e91bc98..f0c74255423c 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -74,6 +74,7 @@ struct perf_env {
*/
struct rw_semaphore bpf_info_lock;
struct rb_root bpf_prog_infos;
+ struct rb_root btfs;
};
extern struct perf_env perf_env;
@@ -94,4 +95,6 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env,
struct bpf_prog_info_node *info_node);
struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
__u32 prog_id);
+void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
+struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
#endif /* __PERF_ENV_H */
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 07/11] perf, bpf: save btf in a rbtree in perf_env
2019-02-15 0:00 ` [PATCH v2 perf,bpf 07/11] perf, bpf: save btf in a rbtree in perf_env Song Liu
@ 2019-02-15 14:30 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 14:30 UTC (permalink / raw)
To: Song Liu
Cc: netdev, linux-kernel, ast, daniel, kernel-team, peterz, jolsa, namhyung
Em Thu, Feb 14, 2019 at 04:00:08PM -0800, Song Liu escreveu:
> btf contains information necessary to annotate bpf programs. This patch
> saves btf for bpf programs loaded in the system.
>
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
> tools/perf/util/bpf-event.c | 22 +++++++++++++
> tools/perf/util/bpf-event.h | 7 ++++
> tools/perf/util/env.c | 65 +++++++++++++++++++++++++++++++++++++
> tools/perf/util/env.h | 3 ++
> 4 files changed, 97 insertions(+)
>
> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> index ead599bc4f4e..37a5b8134e00 100644
> --- a/tools/perf/util/bpf-event.c
> +++ b/tools/perf/util/bpf-event.c
> @@ -30,6 +30,27 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
> return 0;
> }
>
> +static int perf_fetch_btf(struct perf_env *env, u32 btf_id, struct btf *btf)
Please use perf_env__fetch_bpf
> +{
> + struct btf_node *node;
> + u32 data_size;
> + const void *data;
> +
> + data = btf__get_raw_data(btf, &data_size);
> +
> + node = malloc(data_size + sizeof(struct btf_node));
> +
> + if (!node)
> + return -1;
> +
> + node->id = btf_id;
> + node->data_size = data_size;
> + memcpy(node->data, data, data_size);
> +
> + perf_env__insert_btf(env, node);
Just like you did above :-)
> + return 0;
> +}
> +
> /*
> * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
> * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
> @@ -109,6 +130,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
> goto out;
> }
> has_btf = true;
> + perf_fetch_btf(env, info->btf_id, btf);
> }
>
> /* Synthesize PERF_RECORD_KSYMBOL */
> diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
> index 11e6730b6105..60ce24e4e5c6 100644
> --- a/tools/perf/util/bpf-event.h
> +++ b/tools/perf/util/bpf-event.h
> @@ -20,6 +20,13 @@ struct bpf_prog_info_node {
> struct rb_node rb_node;
> };
>
> +struct btf_node {
> + struct rb_node rb_node;
> + u32 id;
> + u32 data_size;
> + char data[];
> +};
> +
> #ifdef HAVE_LIBBPF_SUPPORT
> int machine__process_bpf_event(struct machine *machine, union perf_event *event,
> struct perf_sample *sample);
> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
> index 665b6fe3c7b2..6f9e3d4b94bc 100644
> --- a/tools/perf/util/env.c
> +++ b/tools/perf/util/env.c
> @@ -61,6 +61,57 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
> return node;
> }
>
> +void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
> +{
> + struct rb_node *parent = NULL;
> + __u32 btf_id = btf_node->id;
> + struct btf_node *node;
> + struct rb_node **p;
> +
> + down_write(&env->bpf_info_lock);
> + p = &env->btfs.rb_node;
> +
> + while (*p != NULL) {
> + parent = *p;
> + node = rb_entry(parent, struct btf_node, rb_node);
> + if (btf_id < node->id) {
> + p = &(*p)->rb_left;
> + } else if (btf_id > node->id) {
> + p = &(*p)->rb_right;
> + } else {
> + pr_debug("duplicated btf %u\n", btf_id);
goto out:
> + up_write(&env->bpf_info_lock);
> + return;
> + }
> + }
> +
> + rb_link_node(&btf_node->rb_node, parent, p);
> + rb_insert_color(&btf_node->rb_node, &env->btfs);
out:
> + up_write(&env->bpf_info_lock);
> +}
> +
> +struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
> +{
> + struct btf_node *node = NULL;
> + struct rb_node *n;
> +
> + down_read(&env->bpf_info_lock);
> + n = env->btfs.rb_node;
> +
> + while (n) {
> + node = rb_entry(n, struct btf_node, rb_node);
> + if (btf_id < node->id)
> + n = n->rb_left;
> + else if (btf_id > node->id)
> + n = n->rb_right;
> + else
> + break;
> + }
> +
> + up_read(&env->bpf_info_lock);
> + return node;
> +}
> +
> /* purge data in bpf_prog_infos tree */
> static void purge_bpf_info(struct perf_env *env)
The above should've been perf_env__purge_bpf()
> {
> @@ -80,6 +131,19 @@ static void purge_bpf_info(struct perf_env *env)
> rb_erase_init(&node->rb_node, root);
> free(node);
> }
> +
> + root = &env->btfs;
> + next = rb_first(root);
> +
> + while (next) {
> + struct btf_node *node;
> +
> + node = rb_entry(next, struct btf_node, rb_node);
> + next = rb_next(&node->rb_node);
> + rb_erase_init(&node->rb_node, root);
> + free(node);
> + }
> +
> up_write(&env->bpf_info_lock);
> }
>
> @@ -117,6 +181,7 @@ void perf_env__exit(struct perf_env *env)
> static void init_bpf_rb_trees(struct perf_env *env)
> {
> env->bpf_prog_infos = RB_ROOT;
> + env->btfs = RB_ROOT;
> init_rwsem(&env->bpf_info_lock);
> }
>
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index a6d25e91bc98..f0c74255423c 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -74,6 +74,7 @@ struct perf_env {
> */
> struct rw_semaphore bpf_info_lock;
> struct rb_root bpf_prog_infos;
> + struct rb_root btfs;
> };
>
> extern struct perf_env perf_env;
> @@ -94,4 +95,6 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env,
> struct bpf_prog_info_node *info_node);
> struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
> __u32 prog_id);
> +void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
> +struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
> #endif /* __PERF_ENV_H */
> --
> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
` (4 preceding siblings ...)
2019-02-15 0:00 ` [PATCH v2 perf,bpf 07/11] perf, bpf: save btf in a rbtree in perf_env Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 14:26 ` Arnaldo Carvalho de Melo
2019-02-15 0:00 ` [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event Song Liu
6 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
This patch enables perf-record to save btf information as headers to
perf.data A new header type HEADER_BTF is introduced for this data.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
| 99 +++++++++++++++++++++++++++++++++++++++-
| 1 +
2 files changed, 99 insertions(+), 1 deletion(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 2ae76a9d06f6..3f1562afe8e5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1125,6 +1125,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
return ret;
}
+static int write_btf(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;
+ u32 count = 0;
+ int ret;
+
+ down_read(&env->bpf_info_lock);
+
+ root = &env->btfs;
+ next = rb_first(root);
+ while (next) {
+ ++count;
+ next = rb_next(next);
+ }
+
+ ret = do_write(ff, &count, sizeof(count));
+
+ if (ret < 0)
+ goto out;
+
+ next = rb_first(root);
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ ret = do_write(ff, node,
+ sizeof(struct btf_node) + node->data_size);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ up_read(&env->bpf_info_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;
@@ -1628,6 +1667,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
up_read(&env->bpf_info_lock);
}
+static void print_btf(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_info_lock);
+
+ root = &env->btfs;
+ next = rb_first(root);
+
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ fprintf(fp, "# bpf_prog_info of id %u\n", node->id);
+ }
+
+ up_read(&env->bpf_info_lock);
+}
+
static void free_event_desc(struct perf_evsel *events)
{
struct perf_evsel *evsel;
@@ -2723,6 +2784,41 @@ static int process_bpf_prog_info(struct feat_fd *ff,
return err;
}
+static int process_btf(struct feat_fd *ff, void *data __maybe_unused)
+{
+ struct perf_env *env = &ff->ph->env;
+ u32 count, i;
+
+ if (do_read_u32(ff, &count))
+ return -1;
+
+ down_write(&env->bpf_info_lock);
+
+ for (i = 0; i < count; ++i) {
+ struct btf_node btf_node;
+ struct btf_node *node;
+
+ if (__do_read(ff, &btf_node, sizeof(struct btf_node)))
+ return -1;
+
+ node = malloc(sizeof(struct btf_node) + btf_node.data_size);
+ if (!node)
+ return -1;
+
+ node->id = btf_node.id;
+ node->data_size = btf_node.data_size;
+
+ if (__do_read(ff, node->data, btf_node.data_size)) {
+ free(node);
+ return -1;
+ }
+ perf_env__insert_btf(env, node);
+ }
+
+ up_write(&env->bpf_info_lock);
+ return 0;
+}
+
struct feature_ops {
int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2783,7 +2879,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPR(SAMPLE_TIME, sample_time, false),
FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
FEAT_OPR(CLOCKID, clockid, false),
- FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
+ FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
+ FEAT_OPR(BTF, btf, false)
};
struct header_print_data {
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0785c91b4c3a..ba51d8e43c53 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -40,6 +40,7 @@ enum {
HEADER_MEM_TOPOLOGY,
HEADER_CLOCKID,
HEADER_BPF_PROG_INFO,
+ HEADER_BTF,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 0:00 ` [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-02-15 14:26 ` Arnaldo Carvalho de Melo
2019-02-15 17:25 ` Song Liu
0 siblings, 1 reply; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 14:26 UTC (permalink / raw)
To: Song Liu, Jiri Olsa
Cc: netdev, linux-kernel, ast, daniel, kernel-team, peterz, namhyung, acme
Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
> This patch enables perf-record to save btf information as headers to
> perf.data A new header type HEADER_BTF is introduced for this data.
Jiri,
Wouldn't it be better for this HEADER_BTF to be introduced
already as an user space event, Song, see:
tools/perf/util/event.h
and:
tools/perf/util/event.c
perf_event__synthesize_cpu_map()
- Arnaldo
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
> tools/perf/util/header.c | 99 +++++++++++++++++++++++++++++++++++++++-
> tools/perf/util/header.h | 1 +
> 2 files changed, 99 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 2ae76a9d06f6..3f1562afe8e5 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -1125,6 +1125,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
> return ret;
> }
>
> +static int write_btf(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;
> + u32 count = 0;
> + int ret;
> +
> + down_read(&env->bpf_info_lock);
> +
> + root = &env->btfs;
> + next = rb_first(root);
> + while (next) {
> + ++count;
> + next = rb_next(next);
> + }
> +
> + ret = do_write(ff, &count, sizeof(count));
> +
> + if (ret < 0)
> + goto out;
> +
> + next = rb_first(root);
> + while (next) {
> + struct btf_node *node;
> +
> + node = rb_entry(next, struct btf_node, rb_node);
> + next = rb_next(&node->rb_node);
> + ret = do_write(ff, node,
> + sizeof(struct btf_node) + node->data_size);
> + if (ret < 0)
> + goto out;
> + }
> +out:
> + up_read(&env->bpf_info_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;
> @@ -1628,6 +1667,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
> up_read(&env->bpf_info_lock);
> }
>
> +static void print_btf(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_info_lock);
> +
> + root = &env->btfs;
> + next = rb_first(root);
> +
> + while (next) {
> + struct btf_node *node;
> +
> + node = rb_entry(next, struct btf_node, rb_node);
> + next = rb_next(&node->rb_node);
> + fprintf(fp, "# bpf_prog_info of id %u\n", node->id);
> + }
> +
> + up_read(&env->bpf_info_lock);
> +}
> +
> static void free_event_desc(struct perf_evsel *events)
> {
> struct perf_evsel *evsel;
> @@ -2723,6 +2784,41 @@ static int process_bpf_prog_info(struct feat_fd *ff,
> return err;
> }
>
> +static int process_btf(struct feat_fd *ff, void *data __maybe_unused)
> +{
> + struct perf_env *env = &ff->ph->env;
> + u32 count, i;
> +
> + if (do_read_u32(ff, &count))
> + return -1;
> +
> + down_write(&env->bpf_info_lock);
> +
> + for (i = 0; i < count; ++i) {
> + struct btf_node btf_node;
> + struct btf_node *node;
> +
> + if (__do_read(ff, &btf_node, sizeof(struct btf_node)))
> + return -1;
> +
> + node = malloc(sizeof(struct btf_node) + btf_node.data_size);
> + if (!node)
> + return -1;
> +
> + node->id = btf_node.id;
> + node->data_size = btf_node.data_size;
> +
> + if (__do_read(ff, node->data, btf_node.data_size)) {
> + free(node);
> + return -1;
> + }
> + perf_env__insert_btf(env, node);
> + }
> +
> + up_write(&env->bpf_info_lock);
> + return 0;
> +}
> +
> struct feature_ops {
> int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
> void (*print)(struct feat_fd *ff, FILE *fp);
> @@ -2783,7 +2879,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
> FEAT_OPR(SAMPLE_TIME, sample_time, false),
> FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
> FEAT_OPR(CLOCKID, clockid, false),
> - FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
> + FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
> + FEAT_OPR(BTF, btf, false)
> };
>
> struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index 0785c91b4c3a..ba51d8e43c53 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -40,6 +40,7 @@ enum {
> HEADER_MEM_TOPOLOGY,
> HEADER_CLOCKID,
> HEADER_BPF_PROG_INFO,
> + HEADER_BTF,
> HEADER_LAST_FEATURE,
> HEADER_FEAT_BITS = 256,
> };
> --
> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 14:26 ` Arnaldo Carvalho de Melo
@ 2019-02-15 17:25 ` Song Liu
2019-02-15 17:40 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 17:25 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Jiri Olsa, Netdev, linux-kernel, Alexei Starovoitov, daniel,
Kernel Team, peterz, namhyung, acme
> On Feb 15, 2019, at 6:26 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
>
> Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
>> This patch enables perf-record to save btf information as headers to
>> perf.data A new header type HEADER_BTF is introduced for this data.
>
> Jiri,
>
> Wouldn't it be better for this HEADER_BTF to be introduced
> already as an user space event, Song, see:
>
> tools/perf/util/event.h
>
> and:
>
> tools/perf/util/event.c
>
> perf_event__synthesize_cpu_map()
>
> - Arnaldo
>
BTF would be short living for short living BPF programs. I guess
saving them as header is easier than merging them with samples.
What's the benefit of saving them as user space events?
Thanks,
Song
>
>> Signed-off-by: Song Liu <songliubraving@fb.com>
>> ---
>> tools/perf/util/header.c | 99 +++++++++++++++++++++++++++++++++++++++-
>> tools/perf/util/header.h | 1 +
>> 2 files changed, 99 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index 2ae76a9d06f6..3f1562afe8e5 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -1125,6 +1125,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
>> return ret;
>> }
>>
>> +static int write_btf(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;
>> + u32 count = 0;
>> + int ret;
>> +
>> + down_read(&env->bpf_info_lock);
>> +
>> + root = &env->btfs;
>> + next = rb_first(root);
>> + while (next) {
>> + ++count;
>> + next = rb_next(next);
>> + }
>> +
>> + ret = do_write(ff, &count, sizeof(count));
>> +
>> + if (ret < 0)
>> + goto out;
>> +
>> + next = rb_first(root);
>> + while (next) {
>> + struct btf_node *node;
>> +
>> + node = rb_entry(next, struct btf_node, rb_node);
>> + next = rb_next(&node->rb_node);
>> + ret = do_write(ff, node,
>> + sizeof(struct btf_node) + node->data_size);
>> + if (ret < 0)
>> + goto out;
>> + }
>> +out:
>> + up_read(&env->bpf_info_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;
>> @@ -1628,6 +1667,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
>> up_read(&env->bpf_info_lock);
>> }
>>
>> +static void print_btf(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_info_lock);
>> +
>> + root = &env->btfs;
>> + next = rb_first(root);
>> +
>> + while (next) {
>> + struct btf_node *node;
>> +
>> + node = rb_entry(next, struct btf_node, rb_node);
>> + next = rb_next(&node->rb_node);
>> + fprintf(fp, "# bpf_prog_info of id %u\n", node->id);
>> + }
>> +
>> + up_read(&env->bpf_info_lock);
>> +}
>> +
>> static void free_event_desc(struct perf_evsel *events)
>> {
>> struct perf_evsel *evsel;
>> @@ -2723,6 +2784,41 @@ static int process_bpf_prog_info(struct feat_fd *ff,
>> return err;
>> }
>>
>> +static int process_btf(struct feat_fd *ff, void *data __maybe_unused)
>> +{
>> + struct perf_env *env = &ff->ph->env;
>> + u32 count, i;
>> +
>> + if (do_read_u32(ff, &count))
>> + return -1;
>> +
>> + down_write(&env->bpf_info_lock);
>> +
>> + for (i = 0; i < count; ++i) {
>> + struct btf_node btf_node;
>> + struct btf_node *node;
>> +
>> + if (__do_read(ff, &btf_node, sizeof(struct btf_node)))
>> + return -1;
>> +
>> + node = malloc(sizeof(struct btf_node) + btf_node.data_size);
>> + if (!node)
>> + return -1;
>> +
>> + node->id = btf_node.id;
>> + node->data_size = btf_node.data_size;
>> +
>> + if (__do_read(ff, node->data, btf_node.data_size)) {
>> + free(node);
>> + return -1;
>> + }
>> + perf_env__insert_btf(env, node);
>> + }
>> +
>> + up_write(&env->bpf_info_lock);
>> + return 0;
>> +}
>> +
>> struct feature_ops {
>> int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
>> void (*print)(struct feat_fd *ff, FILE *fp);
>> @@ -2783,7 +2879,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
>> FEAT_OPR(SAMPLE_TIME, sample_time, false),
>> FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
>> FEAT_OPR(CLOCKID, clockid, false),
>> - FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
>> + FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
>> + FEAT_OPR(BTF, btf, false)
>> };
>>
>> struct header_print_data {
>> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
>> index 0785c91b4c3a..ba51d8e43c53 100644
>> --- a/tools/perf/util/header.h
>> +++ b/tools/perf/util/header.h
>> @@ -40,6 +40,7 @@ enum {
>> HEADER_MEM_TOPOLOGY,
>> HEADER_CLOCKID,
>> HEADER_BPF_PROG_INFO,
>> + HEADER_BTF,
>> HEADER_LAST_FEATURE,
>> HEADER_FEAT_BITS = 256,
>> };
>> --
>> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 17:25 ` Song Liu
@ 2019-02-15 17:40 ` Arnaldo Carvalho de Melo
2019-02-15 17:47 ` Song Liu
0 siblings, 1 reply; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 17:40 UTC (permalink / raw)
To: Song Liu, Jiri Olsa, Stephane Eranian
Cc: Netdev, linux-kernel, Alexei Starovoitov, daniel, Kernel Team,
peterz, namhyung
Em Fri, Feb 15, 2019 at 05:25:01PM +0000, Song Liu escreveu:
> > On Feb 15, 2019, at 6:26 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> > Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
> >> This patch enables perf-record to save btf information as headers to
> >> perf.data A new header type HEADER_BTF is introduced for this data.
> > Wouldn't it be better for this HEADER_BTF to be introduced
> > already as an user space event, Song, see:
> > tools/perf/util/event.h
> > and:
> > tools/perf/util/event.c
> > perf_event__synthesize_cpu_map()
> BTF would be short living for short living BPF programs. I guess
> saving them as header is easier than merging them with samples.
> What's the benefit of saving them as user space events?
When we work with pipe mode, i.e.:
perf record -o - | perf report -i -
and other combinations (with 'perf script', 'perf inject', etc), we need
a way to pass the headers to the other side, and the way was via user
space events.
This is something Stephane and Jiri have been discussing recently,
probably they have more justifications, Stephane, Jiri?
- Arnaldo
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 17:40 ` Arnaldo Carvalho de Melo
@ 2019-02-15 17:47 ` Song Liu
2019-02-15 18:20 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 17:47 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Jiri Olsa, Stephane Eranian, Netdev, linux-kernel,
Alexei Starovoitov, daniel, Kernel Team, peterz, namhyung
> On Feb 15, 2019, at 9:40 AM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> Em Fri, Feb 15, 2019 at 05:25:01PM +0000, Song Liu escreveu:
>>> On Feb 15, 2019, at 6:26 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
>>> Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
>>>> This patch enables perf-record to save btf information as headers to
>>>> perf.data A new header type HEADER_BTF is introduced for this data.
>
>>> Wouldn't it be better for this HEADER_BTF to be introduced
>>> already as an user space event, Song, see:
>
>>> tools/perf/util/event.h
>
>>> and:
>
>>> tools/perf/util/event.c
>
>>> perf_event__synthesize_cpu_map()
>
>> BTF would be short living for short living BPF programs. I guess
>> saving them as header is easier than merging them with samples.
>
>> What's the benefit of saving them as user space events?
>
> When we work with pipe mode, i.e.:
>
> perf record -o - | perf report -i -
>
> and other combinations (with 'perf script', 'perf inject', etc), we need
> a way to pass the headers to the other side, and the way was via user
> space events.
>
> This is something Stephane and Jiri have been discussing recently,
> probably they have more justifications, Stephane, Jiri?
>
> - Arnaldo
I see. In this case, we will need some synchronization between main
thread and the polling thread, as they are both writing to the same
pipe.
Thanks,
Song
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 17:47 ` Song Liu
@ 2019-02-15 18:20 ` Arnaldo Carvalho de Melo
2019-02-15 18:59 ` Song Liu
0 siblings, 1 reply; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 18:20 UTC (permalink / raw)
To: Song Liu
Cc: Jiri Olsa, Stephane Eranian, Netdev, linux-kernel,
Alexei Starovoitov, daniel, Kernel Team, peterz, namhyung
Em Fri, Feb 15, 2019 at 05:47:58PM +0000, Song Liu escreveu:
>
>
> > On Feb 15, 2019, at 9:40 AM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> >
> > Em Fri, Feb 15, 2019 at 05:25:01PM +0000, Song Liu escreveu:
> >>> On Feb 15, 2019, at 6:26 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> >>> Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
> >>>> This patch enables perf-record to save btf information as headers to
> >>>> perf.data A new header type HEADER_BTF is introduced for this data.
> >
> >>> Wouldn't it be better for this HEADER_BTF to be introduced
> >>> already as an user space event, Song, see:
> >
> >>> tools/perf/util/event.h
> >
> >>> and:
> >
> >>> tools/perf/util/event.c
> >
> >>> perf_event__synthesize_cpu_map()
> >
> >> BTF would be short living for short living BPF programs. I guess
> >> saving them as header is easier than merging them with samples.
> >
> >> What's the benefit of saving them as user space events?
> >
> > When we work with pipe mode, i.e.:
> >
> > perf record -o - | perf report -i -
> >
> > and other combinations (with 'perf script', 'perf inject', etc), we need
> > a way to pass the headers to the other side, and the way was via user
> > space events.
> >
> > This is something Stephane and Jiri have been discussing recently,
> > probably they have more justifications, Stephane, Jiri?
> >
> > - Arnaldo
>
> I see. In this case, we will need some synchronization between main
> thread and the polling thread, as they are both writing to the same
> pipe.
So, the whole context is that we need to have 'perf record' to start a
thread per CPU and then read the already per-cpu mmap buffers in the
matching thread, with the right affinity, numa settings to have the
record phase not cause contention, etc, so it ends up dumping one stream
per CPU in a separate file in a 'perf.data' directory instead of a
perf.data file.
Jiri is working on that, so, if you dump one more stream into that
directory, it would, at post processing time, be ordered together with
the other stream, the per-cpu ones.
- Arnaldo
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data
2019-02-15 18:20 ` Arnaldo Carvalho de Melo
@ 2019-02-15 18:59 ` Song Liu
0 siblings, 0 replies; 31+ messages in thread
From: Song Liu @ 2019-02-15 18:59 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Jiri Olsa, Stephane Eranian, Netdev, linux-kernel,
Alexei Starovoitov, daniel, Kernel Team, peterz, namhyung
> On Feb 15, 2019, at 10:20 AM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> Em Fri, Feb 15, 2019 at 05:47:58PM +0000, Song Liu escreveu:
>>
>>
>>> On Feb 15, 2019, at 9:40 AM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>>>
>>> Em Fri, Feb 15, 2019 at 05:25:01PM +0000, Song Liu escreveu:
>>>>> On Feb 15, 2019, at 6:26 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
>>>>> Em Thu, Feb 14, 2019 at 04:00:09PM -0800, Song Liu escreveu:
>>>>>> This patch enables perf-record to save btf information as headers to
>>>>>> perf.data A new header type HEADER_BTF is introduced for this data.
>>>
>>>>> Wouldn't it be better for this HEADER_BTF to be introduced
>>>>> already as an user space event, Song, see:
>>>
>>>>> tools/perf/util/event.h
>>>
>>>>> and:
>>>
>>>>> tools/perf/util/event.c
>>>
>>>>> perf_event__synthesize_cpu_map()
>>>
>>>> BTF would be short living for short living BPF programs. I guess
>>>> saving them as header is easier than merging them with samples.
>>>
>>>> What's the benefit of saving them as user space events?
>>>
>>> When we work with pipe mode, i.e.:
>>>
>>> perf record -o - | perf report -i -
>>>
>>> and other combinations (with 'perf script', 'perf inject', etc), we need
>>> a way to pass the headers to the other side, and the way was via user
>>> space events.
>>>
>>> This is something Stephane and Jiri have been discussing recently,
>>> probably they have more justifications, Stephane, Jiri?
>>>
>>> - Arnaldo
>>
>> I see. In this case, we will need some synchronization between main
>> thread and the polling thread, as they are both writing to the same
>> pipe.
>
> So, the whole context is that we need to have 'perf record' to start a
> thread per CPU and then read the already per-cpu mmap buffers in the
> matching thread, with the right affinity, numa settings to have the
> record phase not cause contention, etc, so it ends up dumping one stream
> per CPU in a separate file in a 'perf.data' directory instead of a
> perf.data file.
>
> Jiri is working on that, so, if you dump one more stream into that
> directory, it would, at post processing time, be ordered together with
> the other stream, the per-cpu ones.
>
> - Arnaldo
I see. This solution looks great.
For this set, how about I keep this part as-is (at least for v3)? In
this case, it will goes to the header file after Jiri's change. Once
Jiri's work is done, I will move them into per-cpu files.
Thanks,
Song
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event
2019-02-15 0:00 ` [PATCH v2 perf,bpf 02/11] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
` (5 preceding siblings ...)
2019-02-15 0:00 ` [PATCH v2 perf,bpf 08/11] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-02-15 0:00 ` Song Liu
2019-02-15 14:27 ` Arnaldo Carvalho de Melo
6 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 0:00 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
bpf events are only tracked when opts->bpf_event is enabled. This patch
adds command line flag to enable this for perf-top.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/builtin-top.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 27d8d42e0a4d..5271d7211b9c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1492,6 +1492,7 @@ int cmd_top(int argc, const char **argv)
"Display raw encoding of assembly instructions (default)"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
+ OPT_BOOLEAN(0, "bpf-event", &opts->bpf_event, "record bpf events"),
OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
--
2.17.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event
2019-02-15 0:00 ` [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event Song Liu
@ 2019-02-15 14:27 ` Arnaldo Carvalho de Melo
2019-02-15 17:06 ` Song Liu
0 siblings, 1 reply; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 14:27 UTC (permalink / raw)
To: Song Liu
Cc: netdev, linux-kernel, ast, daniel, kernel-team, peterz, jolsa, namhyung
Em Thu, Feb 14, 2019 at 04:00:10PM -0800, Song Liu escreveu:
> bpf events are only tracked when opts->bpf_event is enabled. This patch
> adds command line flag to enable this for perf-top.
Shouldn't this start as enabled and we just provide a way to disable it
for testing purposes? Normally perf top works system wide, and then we
want to get info about BPF events, I think.
- Arnaldo
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
> tools/perf/builtin-top.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 27d8d42e0a4d..5271d7211b9c 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -1492,6 +1492,7 @@ int cmd_top(int argc, const char **argv)
> "Display raw encoding of assembly instructions (default)"),
> OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
> "Enable kernel symbol demangling"),
> + OPT_BOOLEAN(0, "bpf-event", &opts->bpf_event, "record bpf events"),
> OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
> "objdump binary to use for disassembly and annotations"),
> OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
> --
> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event
2019-02-15 14:27 ` Arnaldo Carvalho de Melo
@ 2019-02-15 17:06 ` Song Liu
2019-02-15 18:05 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 31+ messages in thread
From: Song Liu @ 2019-02-15 17:06 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Netdev, linux-kernel, ast, daniel, Kernel Team, peterz, jolsa, namhyung
> On Feb 15, 2019, at 6:27 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
>
> Em Thu, Feb 14, 2019 at 04:00:10PM -0800, Song Liu escreveu:
>> bpf events are only tracked when opts->bpf_event is enabled. This patch
>> adds command line flag to enable this for perf-top.
>
> Shouldn't this start as enabled and we just provide a way to disable it
> for testing purposes? Normally perf top works system wide, and then we
> want to get info about BPF events, I think.
>
> - Arnaldo
We can enable it by default, and add a --no-bpf-event option to disable it
for testing.
Thanks,
Song
>> Signed-off-by: Song Liu <songliubraving@fb.com>
>> ---
>> tools/perf/builtin-top.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
>> index 27d8d42e0a4d..5271d7211b9c 100644
>> --- a/tools/perf/builtin-top.c
>> +++ b/tools/perf/builtin-top.c
>> @@ -1492,6 +1492,7 @@ int cmd_top(int argc, const char **argv)
>> "Display raw encoding of assembly instructions (default)"),
>> OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
>> "Enable kernel symbol demangling"),
>> + OPT_BOOLEAN(0, "bpf-event", &opts->bpf_event, "record bpf events"),
>> OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
>> "objdump binary to use for disassembly and annotations"),
>> OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
>> --
>> 2.17.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 perf,bpf 09/11] perf-top: add option --bpf-event
2019-02-15 17:06 ` Song Liu
@ 2019-02-15 18:05 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 31+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-02-15 18:05 UTC (permalink / raw)
To: Song Liu
Cc: Netdev, linux-kernel, ast, daniel, Kernel Team, peterz, jolsa,
namhyung, acme
Em Fri, Feb 15, 2019 at 05:06:19PM +0000, Song Liu escreveu:
> > On Feb 15, 2019, at 6:27 AM, Arnaldo Carvalho de Melo <acme@redhat.com> wrote:
> > Em Thu, Feb 14, 2019 at 04:00:10PM -0800, Song Liu escreveu:
> >> bpf events are only tracked when opts->bpf_event is enabled. This patch
> >> adds command line flag to enable this for perf-top.
> > Shouldn't this start as enabled and we just provide a way to disable it
> > for testing purposes? Normally perf top works system wide, and then we
> > want to get info about BPF events, I think.
> We can enable it by default, and add a --no-bpf-event option to disable it
> for testing.
Excellent, thanks.
- Arnaldo
^ permalink raw reply [flat|nested] 31+ messages in thread