linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs
@ 2019-03-07 17:57 Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 01/15] perf, bpf: consider events with attr.bpf_event as side-band events Song Liu
                   ` (15 more replies)
  0 siblings, 16 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:57 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

Changes v6 to v7:
1. Fix minor issues suggested by Jiri.

Changes v5 to v6:
1. Improve side band evlist interface;
2. Minor style fixes.

Changes v4 to v5:
1. Rebase to latest bpf-next;
2. Add dependency of 94816add0005 from Arnaldo's tree;
3. More details in change logs;
4. Add perf_env__init() to init bpf related lock and rbtrees;
5. Small clean ups.

Changes v3 to v4:
1. Incorporate feedbacks from Jiri and Namhyung;
2. Fixed compilation error with different feature-disassembler-four-args;
3. Split some patches to smaller patches;
4. Improved error handleing in symbol__disassemble_bpf();
5. Made side band thread more generic;
6. Added comments as suggested.

Changes v2 to v3:
1. Remove unnecessary include in header files;
2. Improved error handling;
3. Better naming of functions, variables, etc.;
4. Enable bpf events by default for perf-top.

Changes v1 to v2:
1. Fix compilation error with different feature-disassembler-four-args;
2. Fix a segfault in perf-record;
3. Split patches 5/9 and 6/9 so that perf_env changes and perf.data changes
   are in separate patches.

This series enables annotation of BPF programs in perf.

perf tool gathers information via sys_bpf and (optionally) stores them in
perf.data as headers.

Patch 1/15 fixes a minor issue in kernel;
Patch 2/15 to 4/15 introduce new helper functions and use them in perf and
     bpftool;
Patch 5/15 to 9/15 saves information of bpf program in perf_env;
Patch 10/15 adds --bpf-event options to perf-top;
Patch 11/15 to 13/15 enables annotation of bpf progs based on information
     gathered in 5/15 to 9/15;
Patch 14/15 introduces side band polling thread that gathers information
     for special kernel events during perf-record or perf-top.
Patch 15/15 handles information of short living BPF program using the new
     side band polling thread.

Commands tested during developments are perf-top, perf-record, perf-report,
and perf-annotate.

===================== Note on patch dependency  ========================
This set has dependency in both bpf-next tree and tip/perf/core. Current
version is developed on bpf-next tree with the following commits
cherry-picked from tip/perf/core (or acme/perf/core):

(from 1/11 to 11/11)
commit 76193a94522f ("perf, bpf: Introduce PERF_RECORD_KSYMBOL")
commit d764ac646491 ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
commit 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT")
commit df063c83aa2c ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
commit 9aa0bfa370b2 ("perf tools: Handle PERF_RECORD_KSYMBOL")
commit 45178a928a4b ("perf tools: Handle PERF_RECORD_BPF_EVENT")
commit 7b612e291a5a ("perf tools: Synthesize PERF_RECORD_* for loaded BPF programs")
commit a40b95bcd30c ("perf top: Synthesize BPF events for pre-existing loaded BPF programs")
commit 6934058d9fb6 ("bpf: Add module name [bpf] to ksymbols for bpf programs")
commit 811184fb6977 ("perf bpf: Fix synthesized PERF_RECORD_KSYMBOL/BPF_EVENT")
comimt 94816add0005 ("perf tools: Add perf_exe() helper to find perf binary")
========================================================================

This set is also available at:

https://github.com/liu-song-6/linux/tree/bpf-annotation

Thanks!!

Song Liu (15):
  perf, bpf: consider events with attr.bpf_event as side-band events
  bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  bpf: bpftool: use bpf_program__get_prog_info_linear() in
    prog.c:do_dump()
  perf, bpf: synthesize bpf events with
    bpf_program__get_prog_info_linear()
  perf: change prototype of perf_event__synthesize_bpf_events()
  perf, bpf: save bpf_prog_info in a rbtree in perf_env
  perf, bpf: save bpf_prog_info information as headers to perf.data
  perf, bpf: save btf in a rbtree in perf_env
  perf, bpf: save btf information as headers to perf.data
  perf-top: add option --no-bpf-event
  perf: add -lopcodes to feature-libbfd
  perf, bpf: enable annotation of bpf program
  perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
  perf: introduce side band thread
  perf, bpf: save bpf_prog_info and btf of short living bpf programs

 kernel/events/core.c         |   3 +-
 tools/bpf/bpftool/prog.c     | 266 +++++++---------------------
 tools/build/Makefile.feature |   6 +-
 tools/lib/bpf/libbpf.c       | 251 +++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h       |  63 +++++++
 tools/lib/bpf/libbpf.map     |   3 +
 tools/perf/Makefile.config   |   6 +-
 tools/perf/builtin-record.c  |   9 +-
 tools/perf/builtin-top.c     |  12 +-
 tools/perf/perf.c            |   1 +
 tools/perf/util/annotate.c   | 150 +++++++++++++++-
 tools/perf/util/bpf-event.c  | 327 ++++++++++++++++++++++++++---------
 tools/perf/util/bpf-event.h  |  33 +++-
 tools/perf/util/dso.c        |   1 +
 tools/perf/util/dso.h        |  33 ++--
 tools/perf/util/env.c        | 149 ++++++++++++++++
 tools/perf/util/env.h        |  22 +++
 tools/perf/util/evlist.c     | 113 ++++++++++++
 tools/perf/util/evlist.h     |  12 ++
 tools/perf/util/evsel.h      |   6 +
 tools/perf/util/header.c     | 250 +++++++++++++++++++++++++-
 tools/perf/util/header.h     |   2 +
 tools/perf/util/session.c    |   1 +
 tools/perf/util/symbol.c     |   1 +
 tools/perf/util/top.h        |   1 +
 25 files changed, 1410 insertions(+), 311 deletions(-)

--
2.17.1

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 01/15] perf, bpf: consider events with attr.bpf_event as side-band events
  2019-03-07 17:57 [PATCH v7 " Song Liu
@ 2019-03-07 17:57 ` Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:57 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

Events with bpf_event should be considered as side-band event, as they
carry information about BPF programs.

Fixes: 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT")
Signed-off-by: Song Liu <songliubraving@fb.com>
---
 kernel/events/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index f1a26c8f15b3..4a59cb9b29ee 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4238,7 +4238,8 @@ static bool is_sb_event(struct perf_event *event)
 	if (attr->mmap || attr->mmap_data || attr->mmap2 ||
 	    attr->comm || attr->comm_exec ||
 	    attr->task || attr->ksymbol ||
-	    attr->context_switch)
+	    attr->context_switch ||
+	    attr->bpf_event)
 		return true;
 	return false;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-07 17:57 [PATCH v7 " Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 01/15] perf, bpf: consider events with attr.bpf_event as side-band events Song Liu
@ 2019-03-07 17:57 ` Song Liu
  2019-03-11 18:26   ` Arnaldo Carvalho de Melo
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:57 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

Currently, bpf_prog_info includes 9 arrays. The user has the option to
fetch any combination of these arrays. However, this requires a lot of
handling of these arrays. This work becomes more tricky when we need to
store bpf_prog_info to a file, because these arrays are allocated
independently.

This patch introduces struct bpf_prog_info_linear, which stores arrays
of bpf_prog_info in continues memory. Helper functions are introduced
to unify the work to get different information of bpf_prog_info.
Specifically, bpf_program__get_prog_info_linear() allows the user to
select which arrays to fetch, and handles details for the user.

Plesae see the comments before enum bpf_prog_info_array for more details
and examples.

Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/lib/bpf/libbpf.c   | 251 +++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h   |  63 ++++++++++
 tools/lib/bpf/libbpf.map |   3 +
 3 files changed, 317 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index f5eb60379c8d..ca00ce5cbae0 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
 # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
 #endif
 
+static inline __u64 ptr_to_u64(const void *ptr)
+{
+	return (__u64) (unsigned long) ptr;
+}
+
 struct bpf_capabilities {
 	/* v4.14: kernel support for program & map names. */
 	__u32 name:1;
@@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
 	ring_buffer_write_tail(header, data_tail);
 	return ret;
 }
+
+struct bpf_prog_info_array_desc {
+	int	array_offset;	/* e.g. offset of jited_prog_insns */
+	int	count_offset;	/* e.g. offset of jited_prog_len */
+	int	size_offset;	/* > 0: offset of rec size,
+				 * < 0: fix size of -size_offset
+				 */
+};
+
+static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
+	[BPF_PROG_INFO_JITED_INSNS] = {
+		offsetof(struct bpf_prog_info, jited_prog_insns),
+		offsetof(struct bpf_prog_info, jited_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_XLATED_INSNS] = {
+		offsetof(struct bpf_prog_info, xlated_prog_insns),
+		offsetof(struct bpf_prog_info, xlated_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_MAP_IDS] = {
+		offsetof(struct bpf_prog_info, map_ids),
+		offsetof(struct bpf_prog_info, nr_map_ids),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_JITED_KSYMS] = {
+		offsetof(struct bpf_prog_info, jited_ksyms),
+		offsetof(struct bpf_prog_info, nr_jited_ksyms),
+		-(int)sizeof(__u64),
+	},
+	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
+		offsetof(struct bpf_prog_info, jited_func_lens),
+		offsetof(struct bpf_prog_info, nr_jited_func_lens),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_FUNC_INFO] = {
+		offsetof(struct bpf_prog_info, func_info),
+		offsetof(struct bpf_prog_info, nr_func_info),
+		offsetof(struct bpf_prog_info, func_info_rec_size),
+	},
+	[BPF_PROG_INFO_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, line_info),
+		offsetof(struct bpf_prog_info, nr_line_info),
+		offsetof(struct bpf_prog_info, line_info_rec_size),
+	},
+	[BPF_PROG_INFO_JITED_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, jited_line_info),
+		offsetof(struct bpf_prog_info, nr_jited_line_info),
+		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
+	},
+	[BPF_PROG_INFO_PROG_TAGS] = {
+		offsetof(struct bpf_prog_info, prog_tags),
+		offsetof(struct bpf_prog_info, nr_prog_tags),
+		-(int)sizeof(__u8) * BPF_TAG_SIZE,
+	},
+
+};
+
+static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u32)];
+	return -(int)offset;
+}
+
+static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u64)];
+	return -(int)offset;
+}
+
+static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
+					 __u32 val)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u32)] = val;
+}
+
+static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
+					 __u64 val)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u64)] = val;
+}
+
+struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info info = {};
+	__u32 info_len = sizeof(info);
+	__u32 data_len = 0;
+	int i, err;
+	void *ptr;
+
+	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
+		return ERR_PTR(-EINVAL);
+
+	/* step 1: get array dimensions */
+	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 2: calculate total size of all arrays */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		bool include_array = (arrays & (1UL << i)) > 0;
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		desc = bpf_prog_info_array_desc + i;
+
+		/* kernel is too old to support this field */
+		if (info_len < desc->array_offset + sizeof(__u32) ||
+		    info_len < desc->count_offset + sizeof(__u32) ||
+		    (desc->size_offset > 0 && info_len < desc->size_offset))
+			include_array = false;
+
+		if (!include_array) {
+			arrays &= ~(1UL << i);	/* clear the bit */
+			continue;
+		}
+
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+
+		data_len += count * size;
+	}
+
+	/* step 3: allocate continuous memory */
+	data_len = roundup(data_len, sizeof(__u64));
+	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
+	if (!info_linear)
+		return ERR_PTR(-ENOMEM);
+
+	/* step 4: fill data to info_linear->info */
+	info_linear->arrays = arrays;
+	memset(&info_linear->info, 0, sizeof(info));
+	ptr = info_linear->data;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->count_offset, count);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->size_offset, size);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset,
+					     ptr_to_u64(ptr));
+		ptr += count * size;
+	}
+
+	/* step 5: call syscall again to get required arrays */
+	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		free(info_linear);
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 6: verify the data */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 v1, v2;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->count_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in element count\n", __func__);
+
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->size_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in rec size\n", __func__);
+	}
+
+	/* step 7: update info_len and data_len */
+	info_linear->info_len = sizeof(struct bpf_prog_info);
+	info_linear->data_len = data_len;
+
+	return info_linear;
+}
+
+void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		offs = addr - ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, offs);
+	}
+}
+
+void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		addr = offs + ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, addr);
+	}
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b4652aa1a58a..c7645a5e1ac0 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -377,6 +377,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
 LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
 				 enum bpf_prog_type prog_type, __u32 ifindex);
 
+/*
+ * Get bpf_prog_info in continuous memory
+ *
+ * struct bpf_prog_info has multiple arrays. The user has option to choose
+ * arrays to fetch from kernel. The following APIs provide uniform way to
+ * fetch these data. All arrays in bpf_prog_info are stored in singile
+ * continuous memory region. This makes it easy to store the info in a
+ * file.
+ *
+ * Before writing bpf_prog_info_linear to files, it is necessary to
+ * translate pointers bpf_prog_info to offsets. Helper functions
+ * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
+ * are introduced to switch between pointers and offsets.
+ *
+ * Examples:
+ *   # To fetch map_ids and prog_tags:
+ *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
+ *           (1UL << BPF_PROG_INFO_PROG_TAGS);
+ *   struct bpf_prog_info_linear *info_linear =
+ *           bpf_program__get_prog_info_linear(fd, arrays);
+ *
+ *   # To save data in file
+ *   bpf_program__bpil_addr_to_offs(info_linear);
+ *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
+ *
+ *   # To read data from file
+ *   read(f, info_linear, <proper_size>);
+ *   bpf_program__bpil_offs_to_addr(info_linear);
+ */
+enum bpf_prog_info_array {
+	BPF_PROG_INFO_FIRST_ARRAY = 0,
+	BPF_PROG_INFO_JITED_INSNS = 0,
+	BPF_PROG_INFO_XLATED_INSNS,
+	BPF_PROG_INFO_MAP_IDS,
+	BPF_PROG_INFO_JITED_KSYMS,
+	BPF_PROG_INFO_JITED_FUNC_LENS,
+	BPF_PROG_INFO_FUNC_INFO,
+	BPF_PROG_INFO_LINE_INFO,
+	BPF_PROG_INFO_JITED_LINE_INFO,
+	BPF_PROG_INFO_PROG_TAGS,
+	BPF_PROG_INFO_LAST_ARRAY,
+};
+
+struct bpf_prog_info_linear {
+	/* size of struct bpf_prog_info, when the tool is compiled */
+	__u32			info_len;
+	/* total bytes allocated for data, round up to 8 bytes */
+	__u32			data_len;
+	/* which arrays are included in data */
+	__u64			arrays;
+	struct bpf_prog_info	info;
+	__u8			data[];
+};
+
+LIBBPF_API struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays);
+
+LIBBPF_API void
+bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
+
+LIBBPF_API void
+bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 778a26702a70..f3ce50500cf2 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
 		xsk_socket__delete;
 		xsk_umem__fd;
 		xsk_socket__fd;
+		bpf_program__get_prog_info_linear;
+		bpf_program__bpil_addr_to_offs;
+		bpf_program__bpil_offs_to_addr;
 } LIBBPF_0.0.1;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
  2019-03-07 17:57 [PATCH v7 " Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 01/15] perf, bpf: consider events with attr.bpf_event as side-band events Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-07 17:57 ` Song Liu
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:57 UTC (permalink / raw)
  To: bpf, 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 8ef80d65a474..d2be5a06c339 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -401,41 +401,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;
@@ -474,175 +464,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.");
 	}
@@ -655,9 +520,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;
@@ -665,19 +530,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];
@@ -685,17 +550,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)
@@ -707,7 +571,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));
@@ -744,49 +608,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] 100+ messages in thread

* [PATCH v7 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (2 preceding siblings ...)
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
@ 2019-03-07 17:57 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:57 UTC (permalink / raw)
  To: bpf, 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] 100+ messages in thread

* [PATCH v7 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events()
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (3 preceding siblings ...)
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

This patch changes the arguments of perf_event__synthesize_bpf_events()
to include perf_session* instead of perf_tool*. perf_session will be used
in the next patch.

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 | 8 +++++---
 tools/perf/util/bpf-event.h | 4 ++--
 4 files changed, 9 insertions(+), 7 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..ff7ee149ec46 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -42,7 +43,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,6 +53,7 @@ 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 *info;
 	struct btf *btf = NULL;
 	bool has_btf = false;
@@ -175,7 +177,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 +211,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..6698683612a7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -15,7 +15,7 @@ struct record_opts;
 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 +27,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)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (4 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, 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.

Some big picture of the next few patches:

To fully annotate BPF programs with source code mapping, 4 different
information are needed:
    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

Before this set, 1) and 2) in the list are already saved to perf.data
file. For BPF programs that are already loaded before perf run, 1) and 2)
are synthesized by perf_event__synthesize_bpf_events(). For short living
BPF programs, 1) and 2) are generated by kernel.

This set handles 3) and 4) from the list. Again, it is necessary to handle
existing BPF program and short living program separately.

This patch handles 3) for exising BPF programs while synthesizing 1) and
2) in perf_event__synthesize_bpf_events(). These data are stored in
perf_env. The next patch saves these data from perf_env to perf.data as
headers.

Similarly, the two patches after the next saves 4) of existing BPF
programs to perf_env and perf.data.

Another patch later will handle 3) and 4) for short living BPF programs
by monitoring 1) and 2) in a dedicate thread.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/perf.c           |  1 +
 tools/perf/util/bpf-event.c | 30 ++++++++++++-
 tools/perf/util/bpf-event.h |  7 +++-
 tools/perf/util/env.c       | 84 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       | 18 ++++++++
 tools/perf/util/session.c   |  1 +
 6 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index a11cb006f968..72df4b6fa36f 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		use_pager = 1;
 	commit_pager_choice();
 
+	perf_env__init(&perf_env);
 	perf_env__set_cmdline(&perf_env, argc, argv);
 	status = p->fn(argc, argv);
 	perf_config__exit();
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index ff7ee149ec46..3ae60f74339b 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "env.h"
 #include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
@@ -54,17 +55,28 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 	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)) {
@@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 						     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,
@@ -167,6 +179,22 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 		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) {
+			err = -1;
+			goto out;
+		}
+
+		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);
 	}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 6698683612a7..fad932f7404f 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,14 +3,19 @@
 #define __PERF_BPF_EVENT_H
 
 #include <linux/compiler.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);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..6e037a9660ca 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,15 +3,93 @@
 #include "env.h"
 #include "sane_ctype.h"
 #include "util.h"
+#include "bpf-event.h"
 #include <errno.h>
 #include <sys/utsname.h>
+#include <bpf/libbpf.h>
 
 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_progs.lock);
+	p = &env->bpf_progs.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);
+			goto out;
+		}
+	}
+
+	rb_link_node(&info_node->rb_node, parent, p);
+	rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
+/* purge data in bpf_progs.infos tree */
+static void perf_env__purge_bpf(struct perf_env *env)
+{
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_write(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		rb_erase(&node->rb_node, root);
+		free(node);
+	}
+	up_write(&env->bpf_progs.lock);
+}
+
 void perf_env__exit(struct perf_env *env)
 {
 	int i;
 
+	perf_env__purge_bpf(env);
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -38,6 +116,12 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->memory_nodes);
 }
 
+void perf_env__init(struct perf_env *env)
+{
+	env->bpf_progs.infos = RB_ROOT;
+	init_rwsem(&env->bpf_progs.lock);
+}
+
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
 {
 	int i;
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..e034e5b438e3 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,9 @@
 #define __PERF_ENV_H
 
 #include <linux/types.h>
+#include <linux/rbtree.h>
 #include "cpumap.h"
+#include "rwsem.h"
 
 struct cpu_topology_map {
 	int	socket_id;
@@ -64,8 +66,19 @@ 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 {
+		struct rw_semaphore	lock;
+		struct rb_root		infos;
+	} bpf_progs;
 };
 
+struct bpf_prog_info_node;
+
 extern struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env);
@@ -80,4 +93,9 @@ 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__init(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 */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 026bf04bba74..3c858f1b254e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -129,6 +129,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
 	ordered_events__init(&session->ordered_events,
 			     ordered_events__deliver_event, NULL);
 
+	perf_env__init(&session->header.env);
 	if (data) {
 		if (perf_data__open(data))
 			goto out_delete;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (5 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-11 17:56   ` Jiri Olsa
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, 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>
---
 tools/perf/util/header.c | 145 ++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.h |   1 +
 2 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4b88de5e9192..f0708188211e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -18,6 +18,7 @@
 #include <sys/utsname.h>
 #include <linux/time64.h>
 #include <dirent.h>
+#include <bpf/libbpf.h>
 
 #include "evlist.h"
 #include "evsel.h"
@@ -39,6 +40,7 @@
 #include "tool.h"
 #include "time-utils.h"
 #include "units.h"
+#include "bpf-event.h"
 
 #include "sane_ctype.h"
 
@@ -1074,6 +1076,54 @@ 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_progs.lock);
+
+	root = &env->bpf_progs.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);
+		/*
+		 * translate back to address even when do_write() fails,
+		 * so that this function never changes the data.
+		 */
+		bpf_program__bpil_offs_to_addr(node->info_linear);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1554,6 +1604,29 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
 		ff->ph->env.clockid_res_ns * 1000);
 }
 
+static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
+{
+	struct perf_env *env = &ff->ph->env;
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_read(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		fprintf(fp, "# bpf_prog_info of id %u\n",
+			node->info_linear->info.id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2586,6 +2659,75 @@ static int process_clockid(struct feat_fd *ff,
 	return 0;
 }
 
+static int process_bpf_prog_info(struct feat_fd *ff,
+				 void *data __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+	int err = -1;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		u32 info_len, data_len;
+
+		info_linear = NULL;
+		info_node = NULL;
+		if (do_read_u32(ff, &info_len))
+			goto out;
+		if (do_read_u32(ff, &data_len))
+			goto out;
+
+		if (info_len > sizeof(struct bpf_prog_info)) {
+			pr_warning("detected invalid bpf_prog_info\n");
+			goto out;
+		}
+
+		info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
+				     data_len);
+		if (!info_linear)
+			goto out;
+		info_linear->info_len = sizeof(struct bpf_prog_info);
+		info_linear->data_len = data_len;
+		if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
+			goto out;
+		if (__do_read(ff, &info_linear->info, info_len))
+			goto out;
+		if (info_len < sizeof(struct bpf_prog_info))
+			memset(((void *)(&info_linear->info)) + info_len, 0,
+			       sizeof(struct bpf_prog_info) - info_len);
+
+		if (__do_read(ff, info_linear->data, data_len))
+			goto out;
+
+		info_node = malloc(sizeof(struct bpf_prog_info_node));
+		if (!info_node)
+			goto out;
+
+		/* after reading from file, translate offset to address */
+		bpf_program__bpil_offs_to_addr(info_linear);
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	}
+
+	return 0;
+out:
+	free(info_linear);
+	free(info_node);
+	up_write(&env->bpf_progs.lock);
+	return err;
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2645,7 +2787,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPN(CACHE,		cache,		true),
 	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
 	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
-	FEAT_OPR(CLOCKID,       clockid,        false)
+	FEAT_OPR(CLOCKID,       clockid,        false),
+	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0d553ddca0a3..0785c91b4c3a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,7 @@ enum {
 	HEADER_SAMPLE_TIME,
 	HEADER_MEM_TOPOLOGY,
 	HEADER_CLOCKID,
+	HEADER_BPF_PROG_INFO,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (6 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, 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 | 23 +++++++++++++
 tools/perf/util/bpf-event.h |  7 ++++
 tools/perf/util/env.c       | 65 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       |  4 +++
 4 files changed, 99 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 3ae60f74339b..4ef7c833830c 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -34,6 +34,28 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
 	return 0;
 }
 
+static int perf_env__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
@@ -113,6 +135,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 			goto out;
 		}
 		has_btf = true;
+		perf_env__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 fad932f7404f..b9ec394dc7c7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -16,6 +16,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 6e037a9660ca..d9b1299b8a6d 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -63,6 +63,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_progs.lock);
+	p = &env->bpf_progs.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;
+		}
+	}
+
+	rb_link_node(&btf_node->rb_node, parent, p);
+	rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
 /* purge data in bpf_progs.infos tree */
 static void perf_env__purge_bpf(struct perf_env *env)
 {
@@ -82,6 +133,19 @@ static void perf_env__purge_bpf(struct perf_env *env)
 		rb_erase(&node->rb_node, root);
 		free(node);
 	}
+
+	root = &env->bpf_progs.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(&node->rb_node, root);
+		free(node);
+	}
+
 	up_write(&env->bpf_progs.lock);
 }
 
@@ -119,6 +183,7 @@ void perf_env__exit(struct perf_env *env)
 void perf_env__init(struct perf_env *env)
 {
 	env->bpf_progs.infos = RB_ROOT;
+	env->bpf_progs.btfs = RB_ROOT;
 	init_rwsem(&env->bpf_progs.lock);
 }
 
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index e034e5b438e3..c3e48504e834 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -74,10 +74,12 @@ struct perf_env {
 	struct {
 		struct rw_semaphore	lock;
 		struct rb_root		infos;
+		struct rb_root		btfs;
 	} bpf_progs;
 };
 
 struct bpf_prog_info_node;
+struct btf_node;
 
 extern struct perf_env perf_env;
 
@@ -98,4 +100,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] 100+ messages in thread

* [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (7 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-11 17:56   ` Jiri Olsa
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, 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_BPF_BTF is introduced for this data.

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

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f0708188211e..e31344de20c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1124,6 +1124,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
 	return ret;
 }
 
+static int write_bpf_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_progs.lock);
+
+	root = &env->bpf_progs.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->id,
+			       sizeof(u32) * 2 + node->data_size);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1627,6 +1666,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
 	up_read(&env->bpf_progs.lock);
 }
 
+static void print_bpf_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_progs.lock);
+
+	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2728,6 +2789,49 @@ static int process_bpf_prog_info(struct feat_fd *ff,
 	return err;
 }
 
+static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
+{
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		struct btf_node *node;
+		u32 id, data_size;
+
+		if (do_read_u32(ff, &id))
+			return -1;
+		if (do_read_u32(ff, &data_size))
+			return -1;
+
+		node = malloc(sizeof(struct btf_node) + data_size);
+		if (!node)
+			return -1;
+
+		node->id = id;
+		node->data_size = data_size;
+
+		if (__do_read(ff, node->data, data_size)) {
+			free(node);
+			return -1;
+		}
+
+		perf_env__insert_btf(env, node);
+	}
+
+	up_write(&env->bpf_progs.lock);
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2788,7 +2892,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(BPF_BTF,       bpf_btf,        false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0785c91b4c3a..9e7d931f7c0d 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_BPF_BTF,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 10/15] perf-top: add option --no-bpf-event
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (8 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

bpf events should be tracked by default for perf-top. This patch makes it
on by default, and adds option to disable bpf events.

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

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 27d8d42e0a4d..ccdf5689452f 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, "no-bpf-event", &top.no_bpf_event, "do not 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",
@@ -1651,6 +1652,8 @@ int cmd_top(int argc, const char **argv)
 		signal(SIGWINCH, winch_sig);
 	}
 
+	top.record_opts.bpf_event = !top.no_bpf_event;
+
 	status = __cmd_top(&top);
 
 out_delete_evlist:
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 19f95eaf75c8..862a37bd27ea 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -32,6 +32,7 @@ struct perf_top {
 	bool		   use_tui, use_stdio;
 	bool		   vmlinux_warned;
 	bool		   dump_symtab;
+	bool		   no_bpf_event;
 	struct hist_entry  *sym_filter_entry;
 	struct perf_evsel  *sym_evsel;
 	struct perf_session *session;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (9 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 23:26   ` Stanislav Fomichev
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

Both libbfd and libopcodes are distributed with binutil-dev/devel. When
libbfd presents, it is OK to assume libopcodes also presents. This has
been a safe assumption for bpftool.

This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
used in the next commit for bpf annotation.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/Makefile.config | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index b441c88cafa1..e0bafbc273af 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -701,7 +701,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lopcodes
 else
   # we are on a system that requires -liberty and (maybe) -lz
   # to link against -lbfd; test each case individually here
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (10 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-11 17:56   ` Jiri Olsa
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

This patch enables the annotation of bpf program.

A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
calls into a new function symbol__disassemble_bpf(), where annotation
line information is filled based bpf_prog_info and btf saved in given
perf_env.

symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/build/Makefile.feature |   6 +-
 tools/perf/Makefile.config   |   4 +
 tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
 tools/perf/util/dso.c        |   1 +
 tools/perf/util/dso.h        |  33 +++++---
 tools/perf/util/symbol.c     |   1 +
 6 files changed, 181 insertions(+), 14 deletions(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 5467c6bf9ceb..4f35e9ff1e00 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -71,7 +71,8 @@ FEATURE_TESTS_BASIC :=                  \
         sdt				\
         setns				\
         libopencsd			\
-        libaio
+        libaio				\
+        disassembler-four-args
 
 # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
 # of all feature tests
@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
          lzma                   \
          get_cpuid              \
          bpf			\
-         libaio
+         libaio			\
+         disassembler-four-args
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index e0bafbc273af..ab223239f1fb 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -796,6 +796,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq ($(feature-disassembler-four-args), 1)
+    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
+endif
+
 ifeq (${IS_64_BIT}, 1)
   ifndef NO_PERF_READ_VDSO32
     $(call feature_check,compile-32)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 70de8f6b3aee..e467aa0ef0c2 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -9,6 +9,10 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
 #include "util.h"
 #include "ui/ui.h"
 #include "sort.h"
@@ -22,6 +26,7 @@
 #include "annotate.h"
 #include "evsel.h"
 #include "evlist.h"
+#include "bpf-event.h"
 #include "block-range.h"
 #include "string2.h"
 #include "arch/common.h"
@@ -29,6 +34,9 @@
 #include <pthread.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
+#include <bfd.h>
+#include <dis-asm.h>
+#include <bpf/libbpf.h>
 
 /* FIXME: For the HE_COLORSET */
 #include "ui/browser.h"
@@ -1672,6 +1680,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
 	return 0;
 }
 
+static int symbol__disassemble_bpf(struct symbol *sym,
+				   struct annotate_args *args)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct annotation_options *opts = args->options;
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_linfo *prog_linfo = NULL;
+	struct bpf_prog_info_node *info_node;
+	int len = sym->end - sym->start;
+	disassembler_ftype disassemble;
+	struct map *map = args->ms.map;
+	struct disassemble_info info;
+	struct dso *dso = map->dso;
+	int pc = 0, count, sub_id;
+	struct btf *btf = NULL;
+	char tpath[PATH_MAX];
+	size_t buf_size;
+	int nr_skip = 0;
+	int ret = -1;
+	char *buf;
+	bfd *bfdf;
+	FILE *s;
+
+	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
+		return -1;
+
+	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
+		 sym->name, sym->start, sym->end - sym->start);
+
+	memset(tpath, 0, sizeof(tpath));
+	perf_exe(tpath, sizeof(tpath));
+
+	bfdf = bfd_openr(tpath, NULL);
+	assert(bfdf);
+	assert(bfd_check_format(bfdf, bfd_object));
+
+	s = open_memstream(&buf, &buf_size);
+	if (!s)
+		goto out;
+	init_disassemble_info(&info, s,
+			      (fprintf_ftype) fprintf);
+
+	info.arch = bfd_get_arch(bfdf);
+	info.mach = bfd_get_mach(bfdf);
+
+	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
+						 dso->bpf_prog.id);
+	if (!info_node)
+		goto out;
+	info_linear = info_node->info_linear;
+	sub_id = dso->bpf_prog.sub_id;
+
+	info.buffer = (void *)(info_linear->info.jited_prog_insns);
+	info.buffer_length = info_linear->info.jited_prog_len;
+
+	if (info_linear->info.nr_line_info)
+		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
+
+	if (info_linear->info.btf_id) {
+		struct btf_node *node;
+
+		node = perf_env__find_btf(dso->bpf_prog.env,
+					  info_linear->info.btf_id);
+		if (node)
+			btf = btf__new((__u8 *)(node->data),
+				       node->data_size);
+	}
+
+	disassemble_init_for_target(&info);
+
+#ifdef DISASM_FOUR_ARGS_SIGNATURE
+	disassemble = disassembler(info.arch,
+				   bfd_big_endian(bfdf),
+				   info.mach,
+				   bfdf);
+#else
+	disassemble = disassembler(bfdf);
+#endif
+	assert(disassemble);
+
+	fflush(s);
+	do {
+		const struct bpf_line_info *linfo = NULL;
+		struct disasm_line *dl;
+		size_t prev_buf_size;
+		const char *srcline;
+		u64 addr;
+
+		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
+		count = disassemble(pc, &info);
+
+		if (prog_linfo)
+			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
+								addr, sub_id,
+								nr_skip);
+
+		if (linfo && btf) {
+			srcline = btf__name_by_offset(btf, linfo->line_off);
+			nr_skip++;
+		} else
+			srcline = NULL;
+
+		fprintf(s, "\n");
+		prev_buf_size = buf_size;
+		fflush(s);
+
+		if (!opts->hide_src_code && srcline) {
+			args->offset = -1;
+			args->line = strdup(srcline);
+			args->line_nr = 0;
+			args->ms.sym  = sym;
+			dl = disasm_line__new(args);
+			if (dl) {
+				annotation_line__add(&dl->al,
+						     &notes->src->source);
+			}
+		}
+
+		args->offset = pc;
+		args->line = buf + prev_buf_size;
+		args->line_nr = 0;
+		args->ms.sym  = sym;
+		dl = disasm_line__new(args);
+		if (dl)
+			annotation_line__add(&dl->al, &notes->src->source);
+
+		pc += count;
+	} while (count > 0 && pc < len);
+
+	ret = 0;
+out:
+	free(prog_linfo);
+	free(btf);
+	fclose(s);
+	bfd_close(bfdf);
+	return ret;
+}
+
 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 {
 	struct annotation_options *opts = args->options;
@@ -1699,7 +1845,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
 		 dso, dso->long_name, sym, sym->name);
 
-	if (dso__is_kcore(dso)) {
+	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+		return symbol__disassemble_bpf(sym, args);
+	} else if (dso__is_kcore(dso)) {
 		kce.kcore_filename = symfs_filename;
 		kce.addr = map__rip_2objdump(map, sym->start);
 		kce.offs = sym->start;
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 62c8cf622607..1798192bf0f9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -181,6 +181,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	case DSO_BINARY_TYPE__KALLSYMS:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
 	case DSO_BINARY_TYPE__JAVA_JIT:
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
 		break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 8c8a7abe809d..f20d319463f1 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,8 @@
 #include "namespaces.h"
 #include "build-id.h"
 
+struct perf_env;
+
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
 	DSO_BINARY_TYPE__GUEST_KALLSYMS,
@@ -34,6 +36,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BPF_PROG_INFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
@@ -177,17 +180,25 @@ struct dso {
 	struct auxtrace_cache *auxtrace_cache;
 	int		 comp;
 
-	/* dso data file */
-	struct {
-		struct rb_root	 cache;
-		int		 fd;
-		int		 status;
-		u32		 status_seen;
-		size_t		 file_size;
-		struct list_head open_entry;
-		u64		 debug_frame_offset;
-		u64		 eh_frame_hdr_offset;
-	} data;
+	union {
+		/* dso data file */
+		struct {
+			struct rb_root	 cache;
+			int		 fd;
+			int		 status;
+			u32		 status_seen;
+			size_t		 file_size;
+			struct list_head open_entry;
+			u64		 debug_frame_offset;
+			u64		 eh_frame_hdr_offset;
+		} data;
+		/* bpf prog information */
+		struct {
+			u32		id;
+			u32		sub_id;
+			struct perf_env	*env;
+		} bpf_prog;
+	};
 
 	union { /* Tool specific area */
 		void	 *priv;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 48efad6d0f90..33ae59e89da2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1441,6 +1441,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
 		return true;
 
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 	default:
 		return false;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (11 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 14/15] perf: introduce side band thread Song Liu
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

This patch adds processing of PERF_BPF_EVENT_PROG_LOAD, which sets proper
DSO type/id/etc of memory regions mapped to BPF programs to
DSO_BINARY_TYPE__BPF_PROG_INFO

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/util/bpf-event.c | 53 +++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 4ef7c833830c..c0a316af5c2a 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -25,12 +25,65 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
 	return ret;
 }
 
+static int machine__process_bpf_event_load(struct machine *machine,
+					   union perf_event *event,
+					   struct perf_sample *sample __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = machine->env;
+	int id = event->bpf_event.id;
+	unsigned int i;
+
+	/* perf-record, no need to handle bpf-event */
+	if (env == NULL)
+		return 0;
+
+	info_node = perf_env__find_bpf_prog_info(env, id);
+	if (!info_node)
+		return 0;
+	info_linear = info_node->info_linear;
+
+	for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
+		u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
+		u64 addr = addrs[i];
+		struct map *map;
+
+		map = map_groups__find(&machine->kmaps, addr);
+
+		if (map) {
+			map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
+			map->dso->bpf_prog.id = id;
+			map->dso->bpf_prog.sub_id = i;
+			map->dso->bpf_prog.env = env;
+		}
+	}
+	return 0;
+}
+
 int machine__process_bpf_event(struct machine *machine __maybe_unused,
 			       union perf_event *event,
 			       struct perf_sample *sample __maybe_unused)
 {
 	if (dump_trace)
 		perf_event__fprintf_bpf_event(event, stdout);
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		return machine__process_bpf_event_load(machine, event, sample);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
 	return 0;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 14/15] perf: introduce side band thread
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (12 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-11 17:57   ` Jiri Olsa
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
  2019-03-11 13:59 ` [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs Jiri Olsa
  15 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

This patch introduces side band thread that captures extended information
for events like PERF_RECORD_BPF_EVENT.

This new thread uses its own evlist that uses ring buffer with very low
watermark for lower latency.

To use side band thread, we need to:

1. add side band event(s) by calling perf_evlist__add_sb_event();
2. calls perf_evlist__start_sb_thread();
3. at the end of perf run, perf_evlist__stop_sb_thread().

In the next patch, we use this thread to handle PERF_RECORD_BPF_EVENT.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/builtin-record.c |   5 ++
 tools/perf/builtin-top.c    |   5 ++
 tools/perf/util/evlist.c    | 113 ++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h    |  12 ++++
 tools/perf/util/evsel.h     |   6 ++
 5 files changed, 141 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2355e0a9eda0..435b94f1f3b3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1106,6 +1106,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	struct perf_data *data = &rec->data;
 	struct perf_session *session;
 	bool disabled = false, draining = false;
+	struct perf_evlist *sb_evlist = NULL;
 	int fd;
 
 	atexit(record__sig_exit);
@@ -1206,6 +1207,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
+
 	err = record__synthesize(rec, false);
 	if (err < 0)
 		goto out_child;
@@ -1456,6 +1459,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 out_delete_session:
 	perf_session__delete(session);
+
+	perf_evlist__stop_sb_thread(sb_evlist);
 	return status;
 }
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ccdf5689452f..ec69eb040933 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1524,6 +1524,7 @@ int cmd_top(int argc, const char **argv)
 			"number of thread to run event synthesize"),
 	OPT_END()
 	};
+	struct perf_evlist *sb_evlist = NULL;
 	const char * const top_usage[] = {
 		"perf top [<options>]",
 		NULL
@@ -1654,8 +1655,12 @@ int cmd_top(int argc, const char **argv)
 
 	top.record_opts.bpf_event = !top.no_bpf_event;
 
+	perf_evlist__start_sb_thread(sb_evlist, target);
+
 	status = __cmd_top(&top);
 
+	perf_evlist__stop_sb_thread(sb_evlist);
+
 out_delete_evlist:
 	perf_evlist__delete(top.evlist);
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8c902276d4b4..a06a4f54b083 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@
 #include "debug.h"
 #include "units.h"
 #include "asm/bug.h"
+#include "bpf-event.h"
 #include <signal.h>
 #include <unistd.h>
 
@@ -1841,3 +1842,115 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
 	}
 	return leader;
 }
+
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data)
+{
+	struct perf_evsel *evsel;
+	bool new_evlist = (*evlist) == NULL;
+
+	if (*evlist == NULL)
+		*evlist = perf_evlist__new();
+	if (*evlist == NULL)
+		return -1;
+
+	if (!attr->sample_id_all) {
+		pr_warning("enabling sample_id_all for all side band events\n");
+		attr->sample_id_all = 1;
+	}
+
+	evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries);
+	if (!evsel)
+		goto out_err;
+
+	evsel->side_band.cb = cb;
+	evsel->side_band.data = data;
+	perf_evlist__add(*evlist, evsel);
+	return 0;
+
+out_err:
+	if (new_evlist) {
+		perf_evlist__delete(*evlist);
+		*evlist = NULL;
+	}
+	return -1;
+}
+
+static void *perf_evlist__poll_thread(void *arg)
+{
+	struct perf_evlist *evlist = arg;
+	int i;
+
+	while (!(evlist->thread.done)) {
+		perf_evlist__poll(evlist, 1000);
+
+		for (i = 0; i < evlist->nr_mmaps; i++) {
+			struct perf_mmap *map = &evlist->mmap[i];
+			union perf_event *event;
+
+			if (perf_mmap__read_init(map))
+				continue;
+			while ((event = perf_mmap__read_event(map)) != NULL) {
+				struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
+
+				if (evsel && evsel->side_band.cb)
+					evsel->side_band.cb(event, evsel->side_band.data);
+				else
+					pr_warning("cannot locate proper evsel for the side band event\n");
+
+				perf_mmap__consume(map);
+			}
+			perf_mmap__read_done(map);
+		}
+	}
+	return NULL;
+}
+
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target)
+{
+	struct perf_evsel *counter;
+
+	if (!evlist)
+		return 0;
+
+	if (perf_evlist__create_maps(evlist, target))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__open(counter, evlist->cpus,
+				     evlist->threads) < 0)
+			goto out_delete_evlist;
+	}
+
+	if (perf_evlist__mmap(evlist, UINT_MAX))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__enable(counter))
+			goto out_delete_evlist;
+	}
+
+	evlist->thread.done = 0;
+	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
+		goto out_delete_evlist;
+
+	return 0;
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	evlist = NULL;
+	return -1;
+}
+
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
+{
+	if (!evlist)
+		return;
+	evlist->thread.done = 1;
+	pthread_join(evlist->thread.th, NULL);
+	perf_evlist__exit(evlist);
+	evlist = NULL;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..07395fbb4b3b 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -51,6 +51,10 @@ struct perf_evlist {
 	struct perf_env	*env;
 	u64		first_sample_time;
 	u64		last_sample_time;
+	struct {
+		pthread_t		th;
+		volatile int		done;
+	} thread;
 };
 
 struct perf_evsel_str_handler {
@@ -84,6 +88,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
 
 int perf_evlist__add_dummy(struct perf_evlist *evlist);
 
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data);
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target);
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist);
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
 			   const char *sys, const char *name, void *handler);
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 29c5eb68c44b..94232ba9acce 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -73,6 +73,8 @@ struct perf_evsel_config_term {
 
 struct perf_stat_evsel;
 
+typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);
+
 /** struct perf_evsel - event selector
  *
  * @evlist - evlist this evsel is in, if it is in one.
@@ -151,6 +153,10 @@ struct perf_evsel {
 	bool			collect_stat;
 	bool			weak_group;
 	const char		*pmu_name;
+	struct {
+		perf_evsel__sb_cb_t	*cb;
+		void			*data;
+	} side_band;
 };
 
 union u64_swap {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v7 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (13 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 14/15] perf: introduce side band thread Song Liu
@ 2019-03-07 17:58 ` Song Liu
  2019-03-11 13:59 ` [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs Jiri Olsa
  15 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 17:58 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu

To fully annotate BPF programs with source code mapping, 4 different
information are needed:
    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

This patch handles 3) and 4) for short living BPF programs. For timely
process of these information, a dedicated event is added to the side
band evlist. When PERF_RECORD_BPF_EVENT is received via the side band
event, the polling thread gathers 3) and 4) vis sys_bpf and store them
in perf_env. These information are saved to perf.data at the end of
perf-record.

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

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 435b94f1f3b3..8d197762a499 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1207,6 +1207,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	if (opts->bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
 	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
 
 	err = record__synthesize(rec, false);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ec69eb040933..0d0da834dd9d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1655,6 +1655,8 @@ int cmd_top(int argc, const char **argv)
 
 	top.record_opts.bpf_event = !top.no_bpf_event;
 
+	if (top.record_opts.bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &perf_env);
 	perf_evlist__start_sb_thread(sb_evlist, target);
 
 	status = __cmd_top(&top);
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index c0a316af5c2a..32766341e111 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -12,6 +12,7 @@
 #include "machine.h"
 #include "env.h"
 #include "session.h"
+#include "evlist.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -329,3 +330,97 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 	free(event);
 	return err;
 }
+
+static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct btf *btf = NULL;
+	u64 arrays;
+	u32 btf_id;
+	int fd;
+
+	fd = bpf_prog_get_fd_by_id(id);
+	if (fd < 0)
+		return;
+
+	arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
+	arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
+	arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
+
+	info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+	if (IS_ERR_OR_NULL(info_linear)) {
+		pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
+		goto out;
+	}
+
+	btf_id = info_linear->info.btf_id;
+
+	info_node = malloc(sizeof(struct bpf_prog_info_node));
+	if (info_node) {
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	} else
+		free(info_linear);
+
+	if (btf_id == 0)
+		goto out;
+
+	if (btf__get_from_id(btf_id, &btf)) {
+		pr_debug("%s: failed to get BTF of id %u, aborting\n",
+			 __func__, btf_id);
+		goto out;
+	}
+	perf_env__fetch_btf(env, btf_id, btf);
+
+out:
+	free(btf);
+	close(fd);
+}
+
+static int bpf_event__sb_cb(union perf_event *event, void *data)
+{
+	struct perf_env *env = data;
+
+	if (event->header.type != PERF_RECORD_BPF_EVENT)
+		return -1;
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		perf_env__add_bpf_info(env, event->bpf_event.id);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
+
+	return 0;
+}
+
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+			    struct perf_env *env)
+{
+	struct perf_event_attr attr = {
+		.type	          = PERF_TYPE_SOFTWARE,
+		.config           = PERF_COUNT_SW_DUMMY,
+		.sample_id_all    = 1,
+		.watermark        = 1,
+		.bpf_event        = 1,
+		.wakeup_watermark = 1,
+		.size	   = sizeof(attr), /* to capture ABI version */
+	};
+
+	return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
+}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index b9ec394dc7c7..249909c826e7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -4,12 +4,17 @@
 
 #include <linux/compiler.h>
 #include <linux/rbtree.h>
+#include <pthread.h>
+#include <api/fd/array.h>
 #include "event.h"
 
 struct machine;
 union perf_event;
+struct perf_env;
 struct perf_sample;
 struct record_opts;
+struct evlist;
+struct target;
 
 struct bpf_prog_info_node {
 	struct bpf_prog_info_linear	*info_linear;
@@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 				      perf_event__handler_t process,
 				      struct machine *machine,
 				      struct record_opts *opts);
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+				 struct perf_env *env);
+
 #else
 static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
 					     union perf_event *event __maybe_unused,
@@ -46,5 +54,12 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
 {
 	return 0;
 }
+
+static int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
+				   struct perf_env *env __maybe_unused)
+{
+	return 0;
+}
+
 #endif // HAVE_LIBBPF_SUPPORT
 #endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
@ 2019-03-07 23:26   ` Stanislav Fomichev
  2019-03-07 23:47     ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Stanislav Fomichev @ 2019-03-07 23:26 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On 03/07, Song Liu wrote:
> Both libbfd and libopcodes are distributed with binutil-dev/devel. When
> libbfd presents, it is OK to assume libopcodes also presents. This has
> been a safe assumption for bpftool.
> 
> This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
> used in the next commit for bpf annotation.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/perf/Makefile.config | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index b441c88cafa1..e0bafbc273af 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -701,7 +701,7 @@ else
>  endif
>  
>  ifeq ($(feature-libbfd), 1)
> -  EXTLIBS += -lbfd
> +  EXTLIBS += -lbfd -lopcodes
I think you need to add -lopcodes to the other feature checks as
well (to work on the systems which require -liberty and/or -lz for
libfd):

--

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index b441c88cafa1..3fa2f5d7d54f 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -701,7 +701,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lopcodes
 else
   # we are on a system that requires -liberty and (maybe) -lz
   # to link against -lbfd; test each case individually here
@@ -712,10 +712,10 @@ else
   $(call feature_check,libbfd-liberty-z)
 
   ifeq ($(feature-libbfd-liberty), 1)
-    EXTLIBS += -lbfd -liberty
+    EXTLIBS += -lbfd -lopcodes -liberty
   else
     ifeq ($(feature-libbfd-liberty-z), 1)
-      EXTLIBS += -lbfd -liberty -lz
+      EXTLIBS += -lbfd -lopcodes -liberty -lz
     endif
   endif
 endif

>  else
>    # we are on a system that requires -liberty and (maybe) -lz
>    # to link against -lbfd; test each case individually here
> -- 
> 2.17.1
> 

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd
  2019-03-07 23:26   ` Stanislav Fomichev
@ 2019-03-07 23:47     ` Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-07 23:47 UTC (permalink / raw)
  To: Stanislav Fomichev
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, jolsa, namhyung



> On Mar 7, 2019, at 3:26 PM, Stanislav Fomichev <sdf@fomichev.me> wrote:
> 
> On 03/07, Song Liu wrote:
>> Both libbfd and libopcodes are distributed with binutil-dev/devel. When
>> libbfd presents, it is OK to assume libopcodes also presents. This has
>> been a safe assumption for bpftool.
>> 
>> This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
>> used in the next commit for bpf annotation.
>> 
>> Signed-off-by: Song Liu <songliubraving@fb.com>
>> ---
>> tools/perf/Makefile.config | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
>> index b441c88cafa1..e0bafbc273af 100644
>> --- a/tools/perf/Makefile.config
>> +++ b/tools/perf/Makefile.config
>> @@ -701,7 +701,7 @@ else
>> endif
>> 
>> ifeq ($(feature-libbfd), 1)
>> -  EXTLIBS += -lbfd
>> +  EXTLIBS += -lbfd -lopcodes
> I think you need to add -lopcodes to the other feature checks as
> well (to work on the systems which require -liberty and/or -lz for
> libfd):
> 
> --
> 
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index b441c88cafa1..3fa2f5d7d54f 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -701,7 +701,7 @@ else
> endif
> 
> ifeq ($(feature-libbfd), 1)
> -  EXTLIBS += -lbfd
> +  EXTLIBS += -lbfd -lopcodes
> else
>   # we are on a system that requires -liberty and (maybe) -lz
>   # to link against -lbfd; test each case individually here
> @@ -712,10 +712,10 @@ else
>   $(call feature_check,libbfd-liberty-z)
> 
>   ifeq ($(feature-libbfd-liberty), 1)
> -    EXTLIBS += -lbfd -liberty
> +    EXTLIBS += -lbfd -lopcodes -liberty
>   else
>     ifeq ($(feature-libbfd-liberty-z), 1)
> -      EXTLIBS += -lbfd -liberty -lz
> +      EXTLIBS += -lbfd -lopcodes -liberty -lz
>     endif
>   endif
> endif

Good point! I will fix it in next version. 

Thanks,
Song

> 
>> else
>>   # we are on a system that requires -liberty and (maybe) -lz
>>   # to link against -lbfd; test each case individually here
>> -- 
>> 2.17.1


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs
  2019-03-07 17:57 [PATCH v7 " Song Liu
                   ` (14 preceding siblings ...)
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
@ 2019-03-11 13:59 ` Jiri Olsa
  2019-03-11 14:16   ` Song Liu
  15 siblings, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-11 13:59 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On Thu, Mar 07, 2019 at 09:57:55AM -0800, Song Liu wrote:

SNIP

> ===================== Note on patch dependency  ========================
> This set has dependency in both bpf-next tree and tip/perf/core. Current
> version is developed on bpf-next tree with the following commits
> cherry-picked from tip/perf/core (or acme/perf/core):
> 
> (from 1/11 to 11/11)
> commit 76193a94522f ("perf, bpf: Introduce PERF_RECORD_KSYMBOL")
> commit d764ac646491 ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
> commit 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT")
> commit df063c83aa2c ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
> commit 9aa0bfa370b2 ("perf tools: Handle PERF_RECORD_KSYMBOL")
> commit 45178a928a4b ("perf tools: Handle PERF_RECORD_BPF_EVENT")
> commit 7b612e291a5a ("perf tools: Synthesize PERF_RECORD_* for loaded BPF programs")
> commit a40b95bcd30c ("perf top: Synthesize BPF events for pre-existing loaded BPF programs")
> commit 6934058d9fb6 ("bpf: Add module name [bpf] to ksymbols for bpf programs")
> commit 811184fb6977 ("perf bpf: Fix synthesized PERF_RECORD_KSYMBOL/BPF_EVENT")
> comimt 94816add0005 ("perf tools: Add perf_exe() helper to find perf binary")
> ========================================================================
> 
> This set is also available at:
> 
> https://github.com/liu-song-6/linux/tree/bpf-annotation

could you please update the branch? it seems to have still the old version

thanks,
jirka

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs
  2019-03-11 13:59 ` [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs Jiri Olsa
@ 2019-03-11 14:16   ` Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-11 14:16 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: bpf, Networking, linux-kernel, ast, daniel, Kernel Team, peterz,
	acme, jolsa, namhyung



> On Mar 11, 2019, at 6:59 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Thu, Mar 07, 2019 at 09:57:55AM -0800, Song Liu wrote:
> 
> SNIP
> 
>> ===================== Note on patch dependency  ========================
>> This set has dependency in both bpf-next tree and tip/perf/core. Current
>> version is developed on bpf-next tree with the following commits
>> cherry-picked from tip/perf/core (or acme/perf/core):
>> 
>> (from 1/11 to 11/11)
>> commit 76193a94522f ("perf, bpf: Introduce PERF_RECORD_KSYMBOL")
>> commit d764ac646491 ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
>> commit 6ee52e2a3fe4 ("perf, bpf: Introduce PERF_RECORD_BPF_EVENT")
>> commit df063c83aa2c ("tools headers uapi: Sync tools/include/uapi/linux/perf_event.h")
>> commit 9aa0bfa370b2 ("perf tools: Handle PERF_RECORD_KSYMBOL")
>> commit 45178a928a4b ("perf tools: Handle PERF_RECORD_BPF_EVENT")
>> commit 7b612e291a5a ("perf tools: Synthesize PERF_RECORD_* for loaded BPF programs")
>> commit a40b95bcd30c ("perf top: Synthesize BPF events for pre-existing loaded BPF programs")
>> commit 6934058d9fb6 ("bpf: Add module name [bpf] to ksymbols for bpf programs")
>> commit 811184fb6977 ("perf bpf: Fix synthesized PERF_RECORD_KSYMBOL/BPF_EVENT")
>> comimt 94816add0005 ("perf tools: Add perf_exe() helper to find perf binary")
>> ========================================================================
>> 
>> This set is also available at:
>> 
>> https://github.com/liu-song-6/linux/tree/bpf-annotation
> 
> could you please update the branch? it seems to have still the old version
> 
> thanks,
> jirka

Just updated. Sorry for the confusion. 

Song

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
@ 2019-03-11 17:56   ` Jiri Olsa
  2019-03-11 18:04     ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-11 17:56 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On Thu, Mar 07, 2019 at 09:58:07AM -0800, Song Liu wrote:

SNIP

> +		if (linfo && btf) {
> +			srcline = btf__name_by_offset(btf, linfo->line_off);
> +			nr_skip++;
> +		} else
> +			srcline = NULL;
> +
> +		fprintf(s, "\n");
> +		prev_buf_size = buf_size;
> +		fflush(s);
> +
> +		if (!opts->hide_src_code && srcline) {
> +			args->offset = -1;
> +			args->line = strdup(srcline);
> +			args->line_nr = 0;
> +			args->ms.sym  = sym;
> +			dl = disasm_line__new(args);
> +			if (dl) {
> +				annotation_line__add(&dl->al,
> +						     &notes->src->source);
> +			}
> +		}

I still miss answer for why is the line added twice for
!opts->hide_src_code && srcline ? code up and down

jirka

> +
> +		args->offset = pc;
> +		args->line = buf + prev_buf_size;
> +		args->line_nr = 0;
> +		args->ms.sym  = sym;
> +		dl = disasm_line__new(args);
> +		if (dl)
> +			annotation_line__add(&dl->al, &notes->src->source);
> +
> +		pc += count;
> +	} while (count > 0 && pc < len);

SNIP

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-03-11 17:56   ` Jiri Olsa
  0 siblings, 0 replies; 100+ messages in thread
From: Jiri Olsa @ 2019-03-11 17:56 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On Thu, Mar 07, 2019 at 09:58:04AM -0800, Song Liu wrote:
> This patch enables perf-record to save btf information as headers to
> perf.data A new header type HEADER_BPF_BTF is introduced for this data.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/perf/util/header.c | 107 ++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/header.h |   1 +
>  2 files changed, 107 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index f0708188211e..e31344de20c4 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -1124,6 +1124,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
>  	return ret;
>  }
>  
> +static int write_bpf_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_progs.lock);
> +
> +	root = &env->bpf_progs.btfs;
> +	next = rb_first(root);
> +	while (next) {
> +		++count;
> +		next = rb_next(next);
> +	}

same here.. why you don't keep btf count in perf_env::bpf_progs::btfs_cnt ?

jirka

> +
> +	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->id,
> +			       sizeof(u32) * 2 + node->data_size);
> +		if (ret < 0)
> +			goto out;
> +	}
> +out:
> +	up_read(&env->bpf_progs.lock);
> +	return ret;
> +}
> +
>  static int cpu_cache_level__sort(const void *a, const void *b)
>  {
>  	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
> @@ -1627,6 +1666,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
>  	up_read(&env->bpf_progs.lock);
>  }
>  
> +static void print_bpf_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_progs.lock);
> +
> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
> +	}
> +
> +	up_read(&env->bpf_progs.lock);
> +}
> +
>  static void free_event_desc(struct perf_evsel *events)
>  {
>  	struct perf_evsel *evsel;
> @@ -2728,6 +2789,49 @@ static int process_bpf_prog_info(struct feat_fd *ff,
>  	return err;
>  }
>  
> +static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
> +{
> +	struct perf_env *env = &ff->ph->env;
> +	u32 count, i;
> +
> +	if (ff->ph->needs_swap) {
> +		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
> +		return 0;
> +	}
> +
> +	if (do_read_u32(ff, &count))
> +		return -1;
> +
> +	down_write(&env->bpf_progs.lock);
> +
> +	for (i = 0; i < count; ++i) {
> +		struct btf_node *node;
> +		u32 id, data_size;
> +
> +		if (do_read_u32(ff, &id))
> +			return -1;
> +		if (do_read_u32(ff, &data_size))
> +			return -1;
> +
> +		node = malloc(sizeof(struct btf_node) + data_size);
> +		if (!node)
> +			return -1;
> +
> +		node->id = id;
> +		node->data_size = data_size;
> +
> +		if (__do_read(ff, node->data, data_size)) {
> +			free(node);
> +			return -1;
> +		}
> +
> +		perf_env__insert_btf(env, node);
> +	}
> +
> +	up_write(&env->bpf_progs.lock);
> +	return 0;
> +}
> +
>  struct feature_ops {
>  	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
>  	void (*print)(struct feat_fd *ff, FILE *fp);
> @@ -2788,7 +2892,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(BPF_BTF,       bpf_btf,        false)
>  };
>  
>  struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index 0785c91b4c3a..9e7d931f7c0d 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_BPF_BTF,
>  	HEADER_LAST_FEATURE,
>  	HEADER_FEAT_BITS	= 256,
>  };
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
@ 2019-03-11 17:56   ` Jiri Olsa
  2019-03-11 18:05     ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-11 17:56 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On Thu, Mar 07, 2019 at 09:58:02AM -0800, Song Liu wrote:
> This patch enables perf-record to save bpf_prog_info information as
> headers to perf.data. A new header type HEADER_BPF_PROG_INFO is
> introduced for this data.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/perf/util/header.c | 145 ++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/header.h |   1 +
>  2 files changed, 145 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 4b88de5e9192..f0708188211e 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -18,6 +18,7 @@
>  #include <sys/utsname.h>
>  #include <linux/time64.h>
>  #include <dirent.h>
> +#include <bpf/libbpf.h>
>  
>  #include "evlist.h"
>  #include "evsel.h"
> @@ -39,6 +40,7 @@
>  #include "tool.h"
>  #include "time-utils.h"
>  #include "units.h"
> +#include "bpf-event.h"
>  
>  #include "sane_ctype.h"
>  
> @@ -1074,6 +1076,54 @@ 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_progs.lock);
> +
> +	root = &env->bpf_progs.infos;
> +	next = rb_first(root);
> +	while (next) {
> +		++count;
> +		next = rb_next(next);
> +	}

sry I did not se this before, but why you don't keep program count
in perf_env::bpf_progs::infos_cnt ?

jirka

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 14/15] perf: introduce side band thread
  2019-03-07 17:58 ` [PATCH v7 perf,bpf 14/15] perf: introduce side band thread Song Liu
@ 2019-03-11 17:57   ` Jiri Olsa
  0 siblings, 0 replies; 100+ messages in thread
From: Jiri Olsa @ 2019-03-11 17:57 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

On Thu, Mar 07, 2019 at 09:58:09AM -0800, Song Liu wrote:

SNIP

> +static void *perf_evlist__poll_thread(void *arg)
> +{
> +	struct perf_evlist *evlist = arg;
> +	int i;
> +
> +	while (!(evlist->thread.done)) {
> +		perf_evlist__poll(evlist, 1000);
> +
> +		for (i = 0; i < evlist->nr_mmaps; i++) {
> +			struct perf_mmap *map = &evlist->mmap[i];
> +			union perf_event *event;
> +
> +			if (perf_mmap__read_init(map))
> +				continue;
> +			while ((event = perf_mmap__read_event(map)) != NULL) {
> +				struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
> +
> +				if (evsel && evsel->side_band.cb)
> +					evsel->side_band.cb(event, evsel->side_band.data);
> +				else
> +					pr_warning("cannot locate proper evsel for the side band event\n");
> +
> +				perf_mmap__consume(map);
> +			}
> +			perf_mmap__read_done(map);
> +		}

shouldn't you drain the map before leaving?

SNIP

> +out_delete_evlist:
> +	perf_evlist__delete(evlist);
> +	evlist = NULL;
> +	return -1;
> +}
> +
> +void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
> +{
> +	if (!evlist)
> +		return;
> +	evlist->thread.done = 1;
> +	pthread_join(evlist->thread.th, NULL);
> +	perf_evlist__exit(evlist);
> +	evlist = NULL;

I think the interface is ok, but please let this function
undo whatever perf_evlist__start_sb_thread did, so disable
and close events and cleanup maps

thanks,
jirka

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-11 17:56   ` Jiri Olsa
@ 2019-03-11 18:04     ` Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-11 18:04 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: bpf, Networking, linux-kernel, ast, daniel, Kernel Team, peterz,
	acme, jolsa, namhyung



> On Mar 11, 2019, at 10:56 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Thu, Mar 07, 2019 at 09:58:07AM -0800, Song Liu wrote:
> 
> SNIP
> 
>> +		if (linfo && btf) {
>> +			srcline = btf__name_by_offset(btf, linfo->line_off);
>> +			nr_skip++;
>> +		} else
>> +			srcline = NULL;
>> +
>> +		fprintf(s, "\n");
>> +		prev_buf_size = buf_size;
>> +		fflush(s);
>> +
>> +		if (!opts->hide_src_code && srcline) {
>> +			args->offset = -1;
>> +			args->line = strdup(srcline);
>> +			args->line_nr = 0;
>> +			args->ms.sym  = sym;
>> +			dl = disasm_line__new(args);
>> +			if (dl) {
>> +				annotation_line__add(&dl->al,
>> +						     &notes->src->source);
>> +			}
>> +		}
> 
> I still miss answer for why is the line added twice for
> !opts->hide_src_code && srcline ? code up and down
> 
> jirka

The line above (under "!hide_src_code && srcline") is the src code 
line; while the one below is the disassemble output. We only show the 
source code when "!hide_src_code && srcline" is true. 

Thanks,
Song

>> +
>> +		args->offset = pc;
>> +		args->line = buf + prev_buf_size;
>> +		args->line_nr = 0;
>> +		args->ms.sym  = sym;
>> +		dl = disasm_line__new(args);
>> +		if (dl)
>> +			annotation_line__add(&dl->al, &notes->src->source);
>> +
>> +		pc += count;
>> +	} while (count > 0 && pc < len);
> 
> SNIP


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-11 17:56   ` Jiri Olsa
@ 2019-03-11 18:05     ` Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-11 18:05 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: bpf, Networking, linux-kernel, ast, daniel, Kernel Team, peterz,
	acme, jolsa, namhyung



> On Mar 11, 2019, at 10:56 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Thu, Mar 07, 2019 at 09:58:02AM -0800, Song Liu wrote:
>> This patch enables perf-record to save bpf_prog_info information as
>> headers to perf.data. A new header type HEADER_BPF_PROG_INFO is
>> introduced for this data.
>> 
>> Signed-off-by: Song Liu <songliubraving@fb.com>
>> ---
>> tools/perf/util/header.c | 145 ++++++++++++++++++++++++++++++++++++++-
>> tools/perf/util/header.h |   1 +
>> 2 files changed, 145 insertions(+), 1 deletion(-)
>> 
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index 4b88de5e9192..f0708188211e 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -18,6 +18,7 @@
>> #include <sys/utsname.h>
>> #include <linux/time64.h>
>> #include <dirent.h>
>> +#include <bpf/libbpf.h>
>> 
>> #include "evlist.h"
>> #include "evsel.h"
>> @@ -39,6 +40,7 @@
>> #include "tool.h"
>> #include "time-utils.h"
>> #include "units.h"
>> +#include "bpf-event.h"
>> 
>> #include "sane_ctype.h"
>> 
>> @@ -1074,6 +1076,54 @@ 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_progs.lock);
>> +
>> +	root = &env->bpf_progs.infos;
>> +	next = rb_first(root);
>> +	while (next) {
>> +		++count;
>> +		next = rb_next(next);
>> +	}
> 
> sry I did not se this before, but why you don't keep program count
> in perf_env::bpf_progs::infos_cnt ?
> 
> jirka

Good idea... I didn't think about this carefully. Will fix in next 
version. 

Thanks,
Song


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-07 17:57 ` [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-11 18:26   ` Arnaldo Carvalho de Melo
  2019-03-11 20:45     ` Daniel Borkmann
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-11 18:26 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov, Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung

Em Thu, Mar 07, 2019 at 09:57:57AM -0800, Song Liu escreveu:
> Currently, bpf_prog_info includes 9 arrays. The user has the option to
> fetch any combination of these arrays. However, this requires a lot of
> handling of these arrays. This work becomes more tricky when we need to
> store bpf_prog_info to a file, because these arrays are allocated
> independently.
> 
> This patch introduces struct bpf_prog_info_linear, which stores arrays
> of bpf_prog_info in continues memory. Helper functions are introduced
> to unify the work to get different information of bpf_prog_info.
> Specifically, bpf_program__get_prog_info_linear() allows the user to
> select which arrays to fetch, and handles details for the user.
> 
> Plesae see the comments before enum bpf_prog_info_array for more details
> and examples.
> 
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>

Daniel, are you ok with these changes to libbpf and bpftool? Perhaps
those should be detached from this patchkit and submitted sooner,
eroding the size of this kit.

Alternatively, if you're ok with it, please provide your Acked-by and
I'll process as soon as I get back to it after Jiri is done reviewing.

- Arnaldo

> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/lib/bpf/libbpf.c   | 251 +++++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h   |  63 ++++++++++
>  tools/lib/bpf/libbpf.map |   3 +
>  3 files changed, 317 insertions(+)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index f5eb60379c8d..ca00ce5cbae0 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
>  # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
>  #endif
>  
> +static inline __u64 ptr_to_u64(const void *ptr)
> +{
> +	return (__u64) (unsigned long) ptr;
> +}
> +
>  struct bpf_capabilities {
>  	/* v4.14: kernel support for program & map names. */
>  	__u32 name:1;
> @@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
>  	ring_buffer_write_tail(header, data_tail);
>  	return ret;
>  }
> +
> +struct bpf_prog_info_array_desc {
> +	int	array_offset;	/* e.g. offset of jited_prog_insns */
> +	int	count_offset;	/* e.g. offset of jited_prog_len */
> +	int	size_offset;	/* > 0: offset of rec size,
> +				 * < 0: fix size of -size_offset
> +				 */
> +};
> +
> +static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
> +	[BPF_PROG_INFO_JITED_INSNS] = {
> +		offsetof(struct bpf_prog_info, jited_prog_insns),
> +		offsetof(struct bpf_prog_info, jited_prog_len),
> +		-1,
> +	},
> +	[BPF_PROG_INFO_XLATED_INSNS] = {
> +		offsetof(struct bpf_prog_info, xlated_prog_insns),
> +		offsetof(struct bpf_prog_info, xlated_prog_len),
> +		-1,
> +	},
> +	[BPF_PROG_INFO_MAP_IDS] = {
> +		offsetof(struct bpf_prog_info, map_ids),
> +		offsetof(struct bpf_prog_info, nr_map_ids),
> +		-(int)sizeof(__u32),
> +	},
> +	[BPF_PROG_INFO_JITED_KSYMS] = {
> +		offsetof(struct bpf_prog_info, jited_ksyms),
> +		offsetof(struct bpf_prog_info, nr_jited_ksyms),
> +		-(int)sizeof(__u64),
> +	},
> +	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
> +		offsetof(struct bpf_prog_info, jited_func_lens),
> +		offsetof(struct bpf_prog_info, nr_jited_func_lens),
> +		-(int)sizeof(__u32),
> +	},
> +	[BPF_PROG_INFO_FUNC_INFO] = {
> +		offsetof(struct bpf_prog_info, func_info),
> +		offsetof(struct bpf_prog_info, nr_func_info),
> +		offsetof(struct bpf_prog_info, func_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_LINE_INFO] = {
> +		offsetof(struct bpf_prog_info, line_info),
> +		offsetof(struct bpf_prog_info, nr_line_info),
> +		offsetof(struct bpf_prog_info, line_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_JITED_LINE_INFO] = {
> +		offsetof(struct bpf_prog_info, jited_line_info),
> +		offsetof(struct bpf_prog_info, nr_jited_line_info),
> +		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_PROG_TAGS] = {
> +		offsetof(struct bpf_prog_info, prog_tags),
> +		offsetof(struct bpf_prog_info, nr_prog_tags),
> +		-(int)sizeof(__u8) * BPF_TAG_SIZE,
> +	},
> +
> +};
> +
> +static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
> +{
> +	__u32 *array = (__u32 *)info;
> +
> +	if (offset >= 0)
> +		return array[offset / sizeof(__u32)];
> +	return -(int)offset;
> +}
> +
> +static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
> +{
> +	__u64 *array = (__u64 *)info;
> +
> +	if (offset >= 0)
> +		return array[offset / sizeof(__u64)];
> +	return -(int)offset;
> +}
> +
> +static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
> +					 __u32 val)
> +{
> +	__u32 *array = (__u32 *)info;
> +
> +	if (offset >= 0)
> +		array[offset / sizeof(__u32)] = val;
> +}
> +
> +static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
> +					 __u64 val)
> +{
> +	__u64 *array = (__u64 *)info;
> +
> +	if (offset >= 0)
> +		array[offset / sizeof(__u64)] = val;
> +}
> +
> +struct bpf_prog_info_linear *
> +bpf_program__get_prog_info_linear(int fd, __u64 arrays)
> +{
> +	struct bpf_prog_info_linear *info_linear;
> +	struct bpf_prog_info info = {};
> +	__u32 info_len = sizeof(info);
> +	__u32 data_len = 0;
> +	int i, err;
> +	void *ptr;
> +
> +	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* step 1: get array dimensions */
> +	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
> +	if (err) {
> +		pr_debug("can't get prog info: %s", strerror(errno));
> +		return ERR_PTR(-EFAULT);
> +	}
> +
> +	/* step 2: calculate total size of all arrays */
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		bool include_array = (arrays & (1UL << i)) > 0;
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 count, size;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +
> +		/* kernel is too old to support this field */
> +		if (info_len < desc->array_offset + sizeof(__u32) ||
> +		    info_len < desc->count_offset + sizeof(__u32) ||
> +		    (desc->size_offset > 0 && info_len < desc->size_offset))
> +			include_array = false;
> +
> +		if (!include_array) {
> +			arrays &= ~(1UL << i);	/* clear the bit */
> +			continue;
> +		}
> +
> +		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +
> +		data_len += count * size;
> +	}
> +
> +	/* step 3: allocate continuous memory */
> +	data_len = roundup(data_len, sizeof(__u64));
> +	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
> +	if (!info_linear)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* step 4: fill data to info_linear->info */
> +	info_linear->arrays = arrays;
> +	memset(&info_linear->info, 0, sizeof(info));
> +	ptr = info_linear->data;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 count, size;
> +
> +		if ((arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +		bpf_prog_info_set_offset_u32(&info_linear->info,
> +					     desc->count_offset, count);
> +		bpf_prog_info_set_offset_u32(&info_linear->info,
> +					     desc->size_offset, size);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset,
> +					     ptr_to_u64(ptr));
> +		ptr += count * size;
> +	}
> +
> +	/* step 5: call syscall again to get required arrays */
> +	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
> +	if (err) {
> +		pr_debug("can't get prog info: %s", strerror(errno));
> +		free(info_linear);
> +		return ERR_PTR(-EFAULT);
> +	}
> +
> +	/* step 6: verify the data */
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 v1, v2;
> +
> +		if ((arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
> +						   desc->count_offset);
> +		if (v1 != v2)
> +			pr_warning("%s: mismatch in element count\n", __func__);
> +
> +		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
> +						   desc->size_offset);
> +		if (v1 != v2)
> +			pr_warning("%s: mismatch in rec size\n", __func__);
> +	}
> +
> +	/* step 7: update info_len and data_len */
> +	info_linear->info_len = sizeof(struct bpf_prog_info);
> +	info_linear->data_len = data_len;
> +
> +	return info_linear;
> +}
> +
> +void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
> +{
> +	int i;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u64 addr, offs;
> +
> +		if ((info_linear->arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
> +						     desc->array_offset);
> +		offs = addr - ptr_to_u64(info_linear->data);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset, offs);
> +	}
> +}
> +
> +void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
> +{
> +	int i;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u64 addr, offs;
> +
> +		if ((info_linear->arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
> +						     desc->array_offset);
> +		addr = offs + ptr_to_u64(info_linear->data);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset, addr);
> +	}
> +}
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index b4652aa1a58a..c7645a5e1ac0 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -377,6 +377,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
>  LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
>  				 enum bpf_prog_type prog_type, __u32 ifindex);
>  
> +/*
> + * Get bpf_prog_info in continuous memory
> + *
> + * struct bpf_prog_info has multiple arrays. The user has option to choose
> + * arrays to fetch from kernel. The following APIs provide uniform way to
> + * fetch these data. All arrays in bpf_prog_info are stored in singile
> + * continuous memory region. This makes it easy to store the info in a
> + * file.
> + *
> + * Before writing bpf_prog_info_linear to files, it is necessary to
> + * translate pointers bpf_prog_info to offsets. Helper functions
> + * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
> + * are introduced to switch between pointers and offsets.
> + *
> + * Examples:
> + *   # To fetch map_ids and prog_tags:
> + *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
> + *           (1UL << BPF_PROG_INFO_PROG_TAGS);
> + *   struct bpf_prog_info_linear *info_linear =
> + *           bpf_program__get_prog_info_linear(fd, arrays);
> + *
> + *   # To save data in file
> + *   bpf_program__bpil_addr_to_offs(info_linear);
> + *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
> + *
> + *   # To read data from file
> + *   read(f, info_linear, <proper_size>);
> + *   bpf_program__bpil_offs_to_addr(info_linear);
> + */
> +enum bpf_prog_info_array {
> +	BPF_PROG_INFO_FIRST_ARRAY = 0,
> +	BPF_PROG_INFO_JITED_INSNS = 0,
> +	BPF_PROG_INFO_XLATED_INSNS,
> +	BPF_PROG_INFO_MAP_IDS,
> +	BPF_PROG_INFO_JITED_KSYMS,
> +	BPF_PROG_INFO_JITED_FUNC_LENS,
> +	BPF_PROG_INFO_FUNC_INFO,
> +	BPF_PROG_INFO_LINE_INFO,
> +	BPF_PROG_INFO_JITED_LINE_INFO,
> +	BPF_PROG_INFO_PROG_TAGS,
> +	BPF_PROG_INFO_LAST_ARRAY,
> +};
> +
> +struct bpf_prog_info_linear {
> +	/* size of struct bpf_prog_info, when the tool is compiled */
> +	__u32			info_len;
> +	/* total bytes allocated for data, round up to 8 bytes */
> +	__u32			data_len;
> +	/* which arrays are included in data */
> +	__u64			arrays;
> +	struct bpf_prog_info	info;
> +	__u8			data[];
> +};
> +
> +LIBBPF_API struct bpf_prog_info_linear *
> +bpf_program__get_prog_info_linear(int fd, __u64 arrays);
> +
> +LIBBPF_API void
> +bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
> +
> +LIBBPF_API void
> +bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
> +
>  #ifdef __cplusplus
>  } /* extern "C" */
>  #endif
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 778a26702a70..f3ce50500cf2 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
>  		xsk_socket__delete;
>  		xsk_umem__fd;
>  		xsk_socket__fd;
> +		bpf_program__get_prog_info_linear;
> +		bpf_program__bpil_addr_to_offs;
> +		bpf_program__bpil_offs_to_addr;
>  } LIBBPF_0.0.1;
> -- 
> 2.17.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-11 18:26   ` Arnaldo Carvalho de Melo
@ 2019-03-11 20:45     ` Daniel Borkmann
  2019-03-11 20:57       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Daniel Borkmann @ 2019-03-11 20:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Alexei Starovoitov, Song Liu
  Cc: bpf, netdev, linux-kernel, ast, kernel-team, peterz, acme, jolsa,
	namhyung

On 03/11/2019 07:26 PM, Arnaldo Carvalho de Melo wrote:
> Em Thu, Mar 07, 2019 at 09:57:57AM -0800, Song Liu escreveu:
>> Currently, bpf_prog_info includes 9 arrays. The user has the option to
>> fetch any combination of these arrays. However, this requires a lot of
>> handling of these arrays. This work becomes more tricky when we need to
>> store bpf_prog_info to a file, because these arrays are allocated
>> independently.
>>
>> This patch introduces struct bpf_prog_info_linear, which stores arrays
>> of bpf_prog_info in continues memory. Helper functions are introduced
>> to unify the work to get different information of bpf_prog_info.
>> Specifically, bpf_program__get_prog_info_linear() allows the user to
>> select which arrays to fetch, and handles details for the user.
>>
>> Plesae see the comments before enum bpf_prog_info_array for more details
>> and examples.
>>
>> Cc: Daniel Borkmann <daniel@iogearbox.net>
>> Cc: Alexei Starovoitov <ast@kernel.org>
> 
> Daniel, are you ok with these changes to libbpf and bpftool? Perhaps
> those should be detached from this patchkit and submitted sooner,
> eroding the size of this kit.
> 
> Alternatively, if you're ok with it, please provide your Acked-by and
> I'll process as soon as I get back to it after Jiri is done reviewing.

Overall looks okay. Are you planning to get these in for 5.1 window? If
yes, that would be great, otherwise we might need to cherry-pick the libbpf
and bpftool ones from your tree into bpf-next as well since there's just
too much going on in this area where we'd potentially run into complex
merge conflicts. In the latter case, libbpf.map would need to be fixed up
to LIBBPF_0.0.3 as convention is that this is in line with kernel release.

Thanks,
Daniel

> - Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-11 20:45     ` Daniel Borkmann
@ 2019-03-11 20:57       ` Arnaldo Carvalho de Melo
  2019-03-12 11:20         ` Daniel Borkmann
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-11 20:57 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: Arnaldo Carvalho de Melo, Alexei Starovoitov, Song Liu, bpf,
	netdev, linux-kernel, ast, kernel-team, peterz, acme, jolsa,
	namhyung

Em Mon, Mar 11, 2019 at 09:45:49PM +0100, Daniel Borkmann escreveu:
> On 03/11/2019 07:26 PM, Arnaldo Carvalho de Melo wrote:
> > Em Thu, Mar 07, 2019 at 09:57:57AM -0800, Song Liu escreveu:
> >> Currently, bpf_prog_info includes 9 arrays. The user has the option to
> >> fetch any combination of these arrays. However, this requires a lot of
> >> handling of these arrays. This work becomes more tricky when we need to
> >> store bpf_prog_info to a file, because these arrays are allocated
> >> independently.
> >>
> >> This patch introduces struct bpf_prog_info_linear, which stores arrays
> >> of bpf_prog_info in continues memory. Helper functions are introduced
> >> to unify the work to get different information of bpf_prog_info.
> >> Specifically, bpf_program__get_prog_info_linear() allows the user to
> >> select which arrays to fetch, and handles details for the user.
> >>
> >> Plesae see the comments before enum bpf_prog_info_array for more details
> >> and examples.
> >>
> >> Cc: Daniel Borkmann <daniel@iogearbox.net>
> >> Cc: Alexei Starovoitov <ast@kernel.org>
> > 
> > Daniel, are you ok with these changes to libbpf and bpftool? Perhaps
> > those should be detached from this patchkit and submitted sooner,
> > eroding the size of this kit.
> > 
> > Alternatively, if you're ok with it, please provide your Acked-by and
> > I'll process as soon as I get back to it after Jiri is done reviewing.
> 
> Overall looks okay. Are you planning to get these in for 5.1 window? If

I hope so.

> yes, that would be great, otherwise we might need to cherry-pick the libbpf

So I'll try and grab those for my next pull req to Ingo, this week,
will add your Acked-by, ok?

> and bpftool ones from your tree into bpf-next as well since there's just
> too much going on in this area where we'd potentially run into complex
> merge conflicts. In the latter case, libbpf.map would need to be fixed up
> to LIBBPF_0.0.3 as convention is that this is in line with kernel release.

BTW, while running my build tests I had to add this to today's batch,
should be trivial when merging, I think, ok?


commit dfcbc2f2994b8a3af3605a26dc29c07ad7378bf4
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 11 17:07:52 2019 -0300

    tools lib bpf: Fix the build by adding a missing stdarg.h include
    
    The libbpf_print_fn_t typedef uses va_list without including the header
    where that type is defined, stdarg.h, breaking in places where we're
    unlucky for that type not to be already defined by some previously
    included header.
    
    Noticed while building on fedora 24 cross building tools/perf to the ARC
    architecture using the uClibc C library:
    
      28 fedora:24-x-ARC-uClibc   : FAIL arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710
    
        CC       /tmp/build/perf/tests/llvm.o
      In file included from tests/llvm.c:3:0:
      /git/linux/tools/lib/bpf/libbpf.h:57:20: error: unknown type name 'va_list'
            const char *, va_list ap);
                          ^~~~~~~
      /git/linux/tools/lib/bpf/libbpf.h:59:34: error: unknown type name 'libbpf_print_fn_t'
       LIBBPF_API void libbpf_set_print(libbpf_print_fn_t fn);
                                        ^~~~~~~~~~~~~~~~~
      mv: cannot stat '/tmp/build/perf/tests/.llvm.o.tmp': No such file or directory
    
    Cc: Alexei Starovoitov <ast@kernel.org>
    Cc: Daniel Borkmann <daniel@iogearbox.net>
    Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
    Cc: Jiri Olsa <jolsa@kernel.org>
    Cc: Namhyung Kim <namhyung@kernel.org>
    Cc: Quentin Monnet <quentin.monnet@netronome.com>
    Cc: Stanislav Fomichev <sdf@google.com>
    Cc: Yonghong Song <yhs@fb.com>
    Fixes: a8a1f7d09cfc ("libbpf: fix libbpf_print")
    Link: https://lkml.kernel.org/n/tip-5270n2quu2gqz22o7itfdx00@git.kernel.org
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b4652aa1a58a..aa1521a51687 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -10,6 +10,7 @@
 #ifndef __LIBBPF_LIBBPF_H
 #define __LIBBPF_LIBBPF_H
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs
@ 2019-03-12  5:30 Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event Song Liu
                   ` (16 more replies)
  0 siblings, 17 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

Changes v8 to v9:
1. Rebase on top of torvalds/master:
    commit ea295481b6e313b4ea3ca2720ffcafd6005b5643 ;
2. Change perf-record option --bpf-event to --no-bpf-event.

Changes v7 to v8:
1. Address issues suggested by Jiri and Stanislav.

Changes v6 to v7:
1. Fix minor issues suggested by Jiri.

Changes v5 to v6:
1. Improve side band evlist interface;
2. Minor style fixes.

Changes v4 to v5:
1. Rebase to latest bpf-next;
2. Add dependency of 94816add0005 from Arnaldo's tree;
3. More details in change logs;
4. Add perf_env__init() to init bpf related lock and rbtrees;
5. Small clean ups.

Changes v3 to v4:
1. Incorporate feedbacks from Jiri and Namhyung;
2. Fixed compilation error with different feature-disassembler-four-args;
3. Split some patches to smaller patches;
4. Improved error handleing in symbol__disassemble_bpf();
5. Made side band thread more generic;
6. Added comments as suggested.

Changes v2 to v3:
1. Remove unnecessary include in header files;
2. Improved error handling;
3. Better naming of functions, variables, etc.;
4. Enable bpf events by default for perf-top.

Changes v1 to v2:
1. Fix compilation error with different feature-disassembler-four-args;
2. Fix a segfault in perf-record;
3. Split patches 5/9 and 6/9 so that perf_env changes and perf.data changes
   are in separate patches.

This series enables annotation of BPF programs in perf.

perf tool gathers information via sys_bpf and (optionally) stores them in
perf.data as headers.

Patch 1/15 changes --bpf-event option to --no-bpf-event;
Patch 2/15 to 4/15 introduce new helper functions and use them in perf and
     bpftool;
Patch 5/15 to 9/15 saves information of bpf program in perf_env;
Patch 10/15 adds --bpf-event options to perf-top;
Patch 11/15 to 13/15 enables annotation of bpf progs based on information
     gathered in 5/15 to 9/15;
Patch 14/15 introduces side band polling thread that gathers information
     for special kernel events during perf-record or perf-top.
Patch 15/15 handles information of short living BPF program using the new
     side band polling thread.

Commands tested during developments are perf-top, perf-record, perf-report,
and perf-annotate.

This set is also available at:

https://github.com/liu-song-6/linux/tree/bpf-annotation-v9

Thanks!!

Song Liu (15):
  perf-record: replace option --bpf-event with --no-bpf-event
  bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  bpf: bpftool: use bpf_program__get_prog_info_linear() in
    prog.c:do_dump()
  perf, bpf: synthesize bpf events with
    bpf_program__get_prog_info_linear()
  perf: change prototype of perf_event__synthesize_bpf_events()
  perf, bpf: save bpf_prog_info in a rbtree in perf_env
  perf, bpf: save bpf_prog_info information as headers to perf.data
  perf, bpf: save btf in a rbtree in perf_env
  perf, bpf: save btf information as headers to perf.data
  perf-top: add option --no-bpf-event
  perf: add -lopcodes to feature-libbfd
  perf, bpf: enable annotation of bpf program
  perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
  perf: introduce side band thread
  perf, bpf: save bpf_prog_info and btf of short living bpf programs

 tools/bpf/bpftool/prog.c     | 266 +++++++---------------------
 tools/build/Makefile.feature |   6 +-
 tools/lib/bpf/libbpf.c       | 251 ++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h       |  63 +++++++
 tools/lib/bpf/libbpf.map     |   3 +
 tools/perf/Makefile.config   |  10 +-
 tools/perf/builtin-record.c  |  11 +-
 tools/perf/builtin-top.c     |  10 +-
 tools/perf/perf.c            |   1 +
 tools/perf/perf.h            |   2 +-
 tools/perf/util/annotate.c   | 150 +++++++++++++++-
 tools/perf/util/bpf-event.c  | 330 ++++++++++++++++++++++++++---------
 tools/perf/util/bpf-event.h  |  33 +++-
 tools/perf/util/dso.c        |   1 +
 tools/perf/util/dso.h        |  32 ++--
 tools/perf/util/env.c        | 151 ++++++++++++++++
 tools/perf/util/env.h        |  24 +++
 tools/perf/util/evlist.c     | 119 +++++++++++++
 tools/perf/util/evlist.h     |  12 ++
 tools/perf/util/evsel.c      |   2 +-
 tools/perf/util/evsel.h      |   6 +
 tools/perf/util/header.c     | 238 ++++++++++++++++++++++++-
 tools/perf/util/header.h     |   2 +
 tools/perf/util/session.c    |   1 +
 tools/perf/util/symbol.c     |   1 +
 25 files changed, 1409 insertions(+), 316 deletions(-)

--
2.17.1

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:35   ` [tip:perf/urgent] perf record: Replace " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

Currently, monitoring of BPF programs through bpf_event is off by default
for perf-record. To turn it on, the user need to use option "--bpf-event".
As BPF gets wider adoption in different subsystems, this option becomes
inconvinient.

This patch makes bpf_event on by default, and adds option "--no-bpf-event"
to turn it off. Since option --bpf-event is not released yet, it is safe
to remove it.

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

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f3f7f3100336..458dcd0cc0e7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1870,7 +1870,7 @@ static struct option __record_options[] = {
 	OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
 		    "synthesize non-sample events at the end of output"),
 	OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
-	OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"),
+	OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "record bpf events"),
 	OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
 		    "Fail if the specified frequency can't be used"),
 	OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index b120e547ddc7..c59743def8d3 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -66,7 +66,7 @@ struct record_opts {
 	bool	     ignore_missing_thread;
 	bool	     strict_freq;
 	bool	     sample_id;
-	bool	     bpf_event;
+	bool	     no_bpf_event;
 	unsigned int freq;
 	unsigned int mmap_pages;
 	unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 028c8ec1f62a..ea012b735a37 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -187,7 +187,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
 	}
 
 	/* Synthesize PERF_RECORD_BPF_EVENT */
-	if (opts->bpf_event) {
+	if (!opts->no_bpf_event) {
 		*bpf_event = (struct bpf_event){
 			.header = {
 				.type = PERF_RECORD_BPF_EVENT,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3bbf73e979c0..bda4a968762d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1036,7 +1036,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
 	attr->mmap2 = track && !perf_missing_features.mmap2;
 	attr->comm  = track;
 	attr->ksymbol = track && !perf_missing_features.ksymbol;
-	attr->bpf_event = track && opts->bpf_event &&
+	attr->bpf_event = track && !opts->no_bpf_event &&
 		!perf_missing_features.bpf_event;
 
 	if (opts->record_namespaces)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-12 13:50   ` Arnaldo Carvalho de Melo
  2019-03-22 22:36   ` [tip:perf/urgent] tools lib bpf: Introduce bpf_program__get_prog_info_linear() tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
                   ` (14 subsequent siblings)
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

Currently, bpf_prog_info includes 9 arrays. The user has the option to
fetch any combination of these arrays. However, this requires a lot of
handling of these arrays. This work becomes more tricky when we need to
store bpf_prog_info to a file, because these arrays are allocated
independently.

This patch introduces struct bpf_prog_info_linear, which stores arrays
of bpf_prog_info in continues memory. Helper functions are introduced
to unify the work to get different information of bpf_prog_info.
Specifically, bpf_program__get_prog_info_linear() allows the user to
select which arrays to fetch, and handles details for the user.

Plesae see the comments before enum bpf_prog_info_array for more details
and examples.

Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/lib/bpf/libbpf.c   | 251 +++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h   |  63 ++++++++++
 tools/lib/bpf/libbpf.map |   3 +
 3 files changed, 317 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index d5b830d60601..98ec9a8cd7af 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
 # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
 #endif
 
+static inline __u64 ptr_to_u64(const void *ptr)
+{
+	return (__u64) (unsigned long) ptr;
+}
+
 struct bpf_capabilities {
 	/* v4.14: kernel support for program & map names. */
 	__u32 name:1;
@@ -2999,3 +3004,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
 	ring_buffer_write_tail(header, data_tail);
 	return ret;
 }
+
+struct bpf_prog_info_array_desc {
+	int	array_offset;	/* e.g. offset of jited_prog_insns */
+	int	count_offset;	/* e.g. offset of jited_prog_len */
+	int	size_offset;	/* > 0: offset of rec size,
+				 * < 0: fix size of -size_offset
+				 */
+};
+
+static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
+	[BPF_PROG_INFO_JITED_INSNS] = {
+		offsetof(struct bpf_prog_info, jited_prog_insns),
+		offsetof(struct bpf_prog_info, jited_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_XLATED_INSNS] = {
+		offsetof(struct bpf_prog_info, xlated_prog_insns),
+		offsetof(struct bpf_prog_info, xlated_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_MAP_IDS] = {
+		offsetof(struct bpf_prog_info, map_ids),
+		offsetof(struct bpf_prog_info, nr_map_ids),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_JITED_KSYMS] = {
+		offsetof(struct bpf_prog_info, jited_ksyms),
+		offsetof(struct bpf_prog_info, nr_jited_ksyms),
+		-(int)sizeof(__u64),
+	},
+	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
+		offsetof(struct bpf_prog_info, jited_func_lens),
+		offsetof(struct bpf_prog_info, nr_jited_func_lens),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_FUNC_INFO] = {
+		offsetof(struct bpf_prog_info, func_info),
+		offsetof(struct bpf_prog_info, nr_func_info),
+		offsetof(struct bpf_prog_info, func_info_rec_size),
+	},
+	[BPF_PROG_INFO_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, line_info),
+		offsetof(struct bpf_prog_info, nr_line_info),
+		offsetof(struct bpf_prog_info, line_info_rec_size),
+	},
+	[BPF_PROG_INFO_JITED_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, jited_line_info),
+		offsetof(struct bpf_prog_info, nr_jited_line_info),
+		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
+	},
+	[BPF_PROG_INFO_PROG_TAGS] = {
+		offsetof(struct bpf_prog_info, prog_tags),
+		offsetof(struct bpf_prog_info, nr_prog_tags),
+		-(int)sizeof(__u8) * BPF_TAG_SIZE,
+	},
+
+};
+
+static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u32)];
+	return -(int)offset;
+}
+
+static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u64)];
+	return -(int)offset;
+}
+
+static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
+					 __u32 val)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u32)] = val;
+}
+
+static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
+					 __u64 val)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u64)] = val;
+}
+
+struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info info = {};
+	__u32 info_len = sizeof(info);
+	__u32 data_len = 0;
+	int i, err;
+	void *ptr;
+
+	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
+		return ERR_PTR(-EINVAL);
+
+	/* step 1: get array dimensions */
+	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 2: calculate total size of all arrays */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		bool include_array = (arrays & (1UL << i)) > 0;
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		desc = bpf_prog_info_array_desc + i;
+
+		/* kernel is too old to support this field */
+		if (info_len < desc->array_offset + sizeof(__u32) ||
+		    info_len < desc->count_offset + sizeof(__u32) ||
+		    (desc->size_offset > 0 && info_len < desc->size_offset))
+			include_array = false;
+
+		if (!include_array) {
+			arrays &= ~(1UL << i);	/* clear the bit */
+			continue;
+		}
+
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+
+		data_len += count * size;
+	}
+
+	/* step 3: allocate continuous memory */
+	data_len = roundup(data_len, sizeof(__u64));
+	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
+	if (!info_linear)
+		return ERR_PTR(-ENOMEM);
+
+	/* step 4: fill data to info_linear->info */
+	info_linear->arrays = arrays;
+	memset(&info_linear->info, 0, sizeof(info));
+	ptr = info_linear->data;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->count_offset, count);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->size_offset, size);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset,
+					     ptr_to_u64(ptr));
+		ptr += count * size;
+	}
+
+	/* step 5: call syscall again to get required arrays */
+	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		free(info_linear);
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 6: verify the data */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 v1, v2;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->count_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in element count\n", __func__);
+
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->size_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in rec size\n", __func__);
+	}
+
+	/* step 7: update info_len and data_len */
+	info_linear->info_len = sizeof(struct bpf_prog_info);
+	info_linear->data_len = data_len;
+
+	return info_linear;
+}
+
+void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		offs = addr - ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, offs);
+	}
+}
+
+void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		addr = offs + ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, addr);
+	}
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b4652aa1a58a..c7645a5e1ac0 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -377,6 +377,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
 LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
 				 enum bpf_prog_type prog_type, __u32 ifindex);
 
+/*
+ * Get bpf_prog_info in continuous memory
+ *
+ * struct bpf_prog_info has multiple arrays. The user has option to choose
+ * arrays to fetch from kernel. The following APIs provide uniform way to
+ * fetch these data. All arrays in bpf_prog_info are stored in singile
+ * continuous memory region. This makes it easy to store the info in a
+ * file.
+ *
+ * Before writing bpf_prog_info_linear to files, it is necessary to
+ * translate pointers bpf_prog_info to offsets. Helper functions
+ * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
+ * are introduced to switch between pointers and offsets.
+ *
+ * Examples:
+ *   # To fetch map_ids and prog_tags:
+ *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
+ *           (1UL << BPF_PROG_INFO_PROG_TAGS);
+ *   struct bpf_prog_info_linear *info_linear =
+ *           bpf_program__get_prog_info_linear(fd, arrays);
+ *
+ *   # To save data in file
+ *   bpf_program__bpil_addr_to_offs(info_linear);
+ *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
+ *
+ *   # To read data from file
+ *   read(f, info_linear, <proper_size>);
+ *   bpf_program__bpil_offs_to_addr(info_linear);
+ */
+enum bpf_prog_info_array {
+	BPF_PROG_INFO_FIRST_ARRAY = 0,
+	BPF_PROG_INFO_JITED_INSNS = 0,
+	BPF_PROG_INFO_XLATED_INSNS,
+	BPF_PROG_INFO_MAP_IDS,
+	BPF_PROG_INFO_JITED_KSYMS,
+	BPF_PROG_INFO_JITED_FUNC_LENS,
+	BPF_PROG_INFO_FUNC_INFO,
+	BPF_PROG_INFO_LINE_INFO,
+	BPF_PROG_INFO_JITED_LINE_INFO,
+	BPF_PROG_INFO_PROG_TAGS,
+	BPF_PROG_INFO_LAST_ARRAY,
+};
+
+struct bpf_prog_info_linear {
+	/* size of struct bpf_prog_info, when the tool is compiled */
+	__u32			info_len;
+	/* total bytes allocated for data, round up to 8 bytes */
+	__u32			data_len;
+	/* which arrays are included in data */
+	__u64			arrays;
+	struct bpf_prog_info	info;
+	__u8			data[];
+};
+
+LIBBPF_API struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays);
+
+LIBBPF_API void
+bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
+
+LIBBPF_API void
+bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 778a26702a70..f3ce50500cf2 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
 		xsk_socket__delete;
 		xsk_umem__fd;
 		xsk_socket__fd;
+		bpf_program__get_prog_info_linear;
+		bpf_program__bpil_addr_to_offs;
+		bpf_program__bpil_offs_to_addr;
 } LIBBPF_0.0.1;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:36   ` [tip:perf/urgent] " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, 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 8ef80d65a474..d2be5a06c339 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -401,41 +401,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;
@@ -474,175 +464,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.");
 	}
@@ -655,9 +520,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;
@@ -665,19 +530,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];
@@ -685,17 +550,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)
@@ -707,7 +571,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));
@@ -744,49 +608,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] 100+ messages in thread

* [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (2 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-13 21:00   ` Arnaldo Carvalho de Melo
  2019-03-22 22:37   ` [tip:perf/urgent] perf bpf: Synthesize " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, 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 ea012b735a37..e9d9854be506 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] 100+ messages in thread

* [PATCH v9 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events()
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (3 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:37   ` [tip:perf/urgent] perf bpf: Make synthesize_bpf_events() receive perf_session pointer instead of perf_tool tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch changes the arguments of perf_event__synthesize_bpf_events()
to include perf_session* instead of perf_tool*. perf_session will be used
in the next patch.

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 | 8 +++++---
 tools/perf/util/bpf-event.h | 4 ++--
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 458dcd0cc0e7..2d34039c4246 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1093,7 +1093,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 231a90daa958..09c0721c97df 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1212,7 +1212,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 e9d9854be506..eedd0f7dfe0c 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -42,7 +43,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,6 +53,7 @@ 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 *info;
 	struct btf *btf = NULL;
 	bool has_btf = false;
@@ -175,7 +177,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 +211,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..6698683612a7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -15,7 +15,7 @@ struct record_opts;
 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 +27,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)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (4 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-12 13:10   ` Jiri Olsa
  2019-03-22 22:38   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
                   ` (10 subsequent siblings)
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, 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.

Some big picture of the next few patches:

To fully annotate BPF programs with source code mapping, 4 different
information are needed:
    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

Before this set, 1) and 2) in the list are already saved to perf.data
file. For BPF programs that are already loaded before perf run, 1) and 2)
are synthesized by perf_event__synthesize_bpf_events(). For short living
BPF programs, 1) and 2) are generated by kernel.

This set handles 3) and 4) from the list. Again, it is necessary to handle
existing BPF program and short living program separately.

This patch handles 3) for exising BPF programs while synthesizing 1) and
2) in perf_event__synthesize_bpf_events(). These data are stored in
perf_env. The next patch saves these data from perf_env to perf.data as
headers.

Similarly, the two patches after the next saves 4) of existing BPF
programs to perf_env and perf.data.

Another patch later will handle 3) and 4) for short living BPF programs
by monitoring 1) and 2) in a dedicate thread.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/perf.c           |  1 +
 tools/perf/util/bpf-event.c | 30 ++++++++++++-
 tools/perf/util/bpf-event.h |  7 ++-
 tools/perf/util/env.c       | 85 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       | 19 +++++++++
 tools/perf/util/session.c   |  1 +
 6 files changed, 141 insertions(+), 2 deletions(-)

diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index a11cb006f968..72df4b6fa36f 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		use_pager = 1;
 	commit_pager_choice();
 
+	perf_env__init(&perf_env);
 	perf_env__set_cmdline(&perf_env, argc, argv);
 	status = p->fn(argc, argv);
 	perf_config__exit();
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index eedd0f7dfe0c..9013f7c29761 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "env.h"
 #include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
@@ -54,17 +55,28 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 	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)) {
@@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 						     machine, process);
 	}
 
-	/* Synthesize PERF_RECORD_BPF_EVENT */
 	if (!opts->no_bpf_event) {
+		/* Synthesize PERF_RECORD_BPF_EVENT */
 		*bpf_event = (struct bpf_event){
 			.header = {
 				.type = PERF_RECORD_BPF_EVENT,
@@ -167,6 +179,22 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 		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) {
+			err = -1;
+			goto out;
+		}
+
+		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);
 	}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 6698683612a7..fad932f7404f 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,14 +3,19 @@
 #define __PERF_BPF_EVENT_H
 
 #include <linux/compiler.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);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..fb82623b0822 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,15 +3,94 @@
 #include "env.h"
 #include "sane_ctype.h"
 #include "util.h"
+#include "bpf-event.h"
 #include <errno.h>
 #include <sys/utsname.h>
+#include <bpf/libbpf.h>
 
 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_progs.lock);
+	p = &env->bpf_progs.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);
+			goto out;
+		}
+	}
+
+	rb_link_node(&info_node->rb_node, parent, p);
+	rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
+	env->bpf_progs.infos_cnt++;
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
+/* purge data in bpf_progs.infos tree */
+static void perf_env__purge_bpf(struct perf_env *env)
+{
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_write(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		rb_erase(&node->rb_node, root);
+		free(node);
+	}
+	up_write(&env->bpf_progs.lock);
+}
+
 void perf_env__exit(struct perf_env *env)
 {
 	int i;
 
+	perf_env__purge_bpf(env);
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -38,6 +117,12 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->memory_nodes);
 }
 
+void perf_env__init(struct perf_env *env)
+{
+	env->bpf_progs.infos = RB_ROOT;
+	init_rwsem(&env->bpf_progs.lock);
+}
+
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
 {
 	int i;
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..24b11c564ba4 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,9 @@
 #define __PERF_ENV_H
 
 #include <linux/types.h>
+#include <linux/rbtree.h>
 #include "cpumap.h"
+#include "rwsem.h"
 
 struct cpu_topology_map {
 	int	socket_id;
@@ -64,8 +66,20 @@ 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 {
+		struct rw_semaphore	lock;
+		struct rb_root		infos;
+		u32			infos_cnt;
+	} bpf_progs;
 };
 
+struct bpf_prog_info_node;
+
 extern struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env);
@@ -80,4 +94,9 @@ 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__init(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 */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index db643f3c2b95..8c5f59efa9b3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -132,6 +132,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
 	ordered_events__init(&session->ordered_events,
 			     ordered_events__deliver_event, NULL);
 
+	perf_env__init(&session->header.env);
 	if (data) {
 		if (perf_data__open(data))
 			goto out_delete;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (5 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-12 13:10   ` Jiri Olsa
                     ` (2 more replies)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
                   ` (9 subsequent siblings)
  16 siblings, 3 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, 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>
---
 tools/perf/util/header.c | 139 ++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.h |   1 +
 2 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 01b324c275b9..a4ef8f657ad0 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -18,6 +18,7 @@
 #include <sys/utsname.h>
 #include <linux/time64.h>
 #include <dirent.h>
+#include <bpf/libbpf.h>
 
 #include "evlist.h"
 #include "evsel.h"
@@ -40,6 +41,7 @@
 #include "time-utils.h"
 #include "units.h"
 #include "cputopo.h"
+#include "bpf-event.h"
 
 #include "sane_ctype.h"
 
@@ -861,6 +863,48 @@ static int write_clockid(struct feat_fd *ff,
 			sizeof(ff->ph->env.clockid_res_ns));
 }
 
+static int write_bpf_prog_info(struct feat_fd *ff,
+			       struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_env *env = &ff->ph->env;
+	struct rb_root *root;
+	struct rb_node *next;
+	int ret;
+
+	down_read(&env->bpf_progs.lock);
+
+	ret = do_write(ff, &env->bpf_progs.infos_cnt,
+		       sizeof(env->bpf_progs.infos_cnt));
+	if (ret < 0)
+		goto out;
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+	while (next) {
+		struct bpf_prog_info_node *node;
+		size_t len;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		len = sizeof(struct bpf_prog_info_linear) +
+			node->info_linear->data_len;
+
+		/* before writing to file, translate address to offset */
+		bpf_program__bpil_addr_to_offs(node->info_linear);
+		ret = do_write(ff, node->info_linear, len);
+		/*
+		 * translate back to address even when do_write() fails,
+		 * so that this function never changes the data.
+		 */
+		bpf_program__bpil_offs_to_addr(node->info_linear);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1341,6 +1385,29 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
 		ff->ph->env.clockid_res_ns * 1000);
 }
 
+static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
+{
+	struct perf_env *env = &ff->ph->env;
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_read(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		fprintf(fp, "# bpf_prog_info of id %u\n",
+			node->info_linear->info.id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2373,6 +2440,75 @@ static int process_clockid(struct feat_fd *ff,
 	return 0;
 }
 
+static int process_bpf_prog_info(struct feat_fd *ff,
+				 void *data __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+	int err = -1;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		u32 info_len, data_len;
+
+		info_linear = NULL;
+		info_node = NULL;
+		if (do_read_u32(ff, &info_len))
+			goto out;
+		if (do_read_u32(ff, &data_len))
+			goto out;
+
+		if (info_len > sizeof(struct bpf_prog_info)) {
+			pr_warning("detected invalid bpf_prog_info\n");
+			goto out;
+		}
+
+		info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
+				     data_len);
+		if (!info_linear)
+			goto out;
+		info_linear->info_len = sizeof(struct bpf_prog_info);
+		info_linear->data_len = data_len;
+		if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
+			goto out;
+		if (__do_read(ff, &info_linear->info, info_len))
+			goto out;
+		if (info_len < sizeof(struct bpf_prog_info))
+			memset(((void *)(&info_linear->info)) + info_len, 0,
+			       sizeof(struct bpf_prog_info) - info_len);
+
+		if (__do_read(ff, info_linear->data, data_len))
+			goto out;
+
+		info_node = malloc(sizeof(struct bpf_prog_info_node));
+		if (!info_node)
+			goto out;
+
+		/* after reading from file, translate offset to address */
+		bpf_program__bpil_offs_to_addr(info_linear);
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	}
+
+	return 0;
+out:
+	free(info_linear);
+	free(info_node);
+	up_write(&env->bpf_progs.lock);
+	return err;
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2432,7 +2568,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPN(CACHE,		cache,		true),
 	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
 	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
-	FEAT_OPR(CLOCKID,       clockid,        false)
+	FEAT_OPR(CLOCKID,       clockid,        false),
+	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0d553ddca0a3..0785c91b4c3a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,7 @@ enum {
 	HEADER_SAMPLE_TIME,
 	HEADER_MEM_TOPOLOGY,
 	HEADER_CLOCKID,
+	HEADER_BPF_PROG_INFO,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (6 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-12 15:00   ` Arnaldo Carvalho de Melo
  2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
                   ` (8 subsequent siblings)
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, 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 | 23 +++++++++++++
 tools/perf/util/bpf-event.h |  7 ++++
 tools/perf/util/env.c       | 66 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       |  5 +++
 4 files changed, 101 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 9013f7c29761..e02a38a98d8d 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -34,6 +34,28 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
 	return 0;
 }
 
+static int perf_env__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
@@ -113,6 +135,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 			goto out;
 		}
 		has_btf = true;
+		perf_env__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 fad932f7404f..b9ec394dc7c7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -16,6 +16,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 fb82623b0822..84bdf726c6a1 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -64,6 +64,58 @@ 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_progs.lock);
+	p = &env->bpf_progs.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;
+		}
+	}
+
+	rb_link_node(&btf_node->rb_node, parent, p);
+	rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
+	env->bpf_progs.btfs_cnt++;
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
 /* purge data in bpf_progs.infos tree */
 static void perf_env__purge_bpf(struct perf_env *env)
 {
@@ -83,6 +135,19 @@ static void perf_env__purge_bpf(struct perf_env *env)
 		rb_erase(&node->rb_node, root);
 		free(node);
 	}
+
+	root = &env->bpf_progs.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(&node->rb_node, root);
+		free(node);
+	}
+
 	up_write(&env->bpf_progs.lock);
 }
 
@@ -120,6 +185,7 @@ void perf_env__exit(struct perf_env *env)
 void perf_env__init(struct perf_env *env)
 {
 	env->bpf_progs.infos = RB_ROOT;
+	env->bpf_progs.btfs = RB_ROOT;
 	init_rwsem(&env->bpf_progs.lock);
 }
 
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 24b11c564ba4..4f8e2b485c01 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -75,10 +75,13 @@ struct perf_env {
 		struct rw_semaphore	lock;
 		struct rb_root		infos;
 		u32			infos_cnt;
+		struct rb_root		btfs;
+		u32			btfs_cnt;
 	} bpf_progs;
 };
 
 struct bpf_prog_info_node;
+struct btf_node;
 
 extern struct perf_env perf_env;
 
@@ -99,4 +102,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] 100+ messages in thread

* [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (7 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-12 15:14   ` Arnaldo Carvalho de Melo
  2019-03-22 22:40   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
                   ` (7 subsequent siblings)
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch enables perf-record to save btf information as headers to
perf.data A new header type HEADER_BPF_BTF is introduced for this data.

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

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a4ef8f657ad0..7decd2d1dbda 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -905,6 +905,39 @@ static int write_bpf_prog_info(struct feat_fd *ff,
 	return ret;
 }
 
+static int write_bpf_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;
+	int ret;
+
+	down_read(&env->bpf_progs.lock);
+
+	ret = do_write(ff, &env->bpf_progs.btfs_cnt,
+		       sizeof(env->bpf_progs.btfs_cnt));
+
+	if (ret < 0)
+		goto out;
+
+	root = &env->bpf_progs.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);
+		ret = do_write(ff, &node->id,
+			       sizeof(u32) * 2 + node->data_size);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1408,6 +1441,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
 	up_read(&env->bpf_progs.lock);
 }
 
+static void print_bpf_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_progs.lock);
+
+	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2509,6 +2564,49 @@ static int process_bpf_prog_info(struct feat_fd *ff,
 	return err;
 }
 
+static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
+{
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		struct btf_node *node;
+		u32 id, data_size;
+
+		if (do_read_u32(ff, &id))
+			return -1;
+		if (do_read_u32(ff, &data_size))
+			return -1;
+
+		node = malloc(sizeof(struct btf_node) + data_size);
+		if (!node)
+			return -1;
+
+		node->id = id;
+		node->data_size = data_size;
+
+		if (__do_read(ff, node->data, data_size)) {
+			free(node);
+			return -1;
+		}
+
+		perf_env__insert_btf(env, node);
+	}
+
+	up_write(&env->bpf_progs.lock);
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2569,7 +2667,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(BPF_BTF,       bpf_btf,        false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0785c91b4c3a..9e7d931f7c0d 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_BPF_BTF,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 10/15] perf-top: add option --no-bpf-event
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (8 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:41   ` [tip:perf/urgent] perf top: Add " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch adds option --no-bpf-event to perf-top, which is the same as
the option of perf-record.

The following patches will use this option.

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 09c0721c97df..63a8f686c5cb 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1480,6 +1480,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, "no-bpf-event", &top.record_opts.no_bpf_event, "do not 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] 100+ messages in thread

* [PATCH v9 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (9 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:41   ` [tip:perf/urgent] perf feature detection: Add " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

Both libbfd and libopcodes are distributed with binutil-dev/devel. When
libbfd presents, it is OK to assume libopcodes also presents. This has
been a safe assumption for bpftool.

This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
used in the next commit for bpf annotation.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/Makefile.config | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 0f11d5891301..df4ad45599ca 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -713,7 +713,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lopcodes
 else
   # we are on a system that requires -liberty and (maybe) -lz
   # to link against -lbfd; test each case individually here
@@ -724,10 +724,10 @@ else
   $(call feature_check,libbfd-liberty-z)
 
   ifeq ($(feature-libbfd-liberty), 1)
-    EXTLIBS += -lbfd -liberty
+    EXTLIBS += -lbfd -lopcodes -liberty
   else
     ifeq ($(feature-libbfd-liberty-z), 1)
-      EXTLIBS += -lbfd -liberty -lz
+      EXTLIBS += -lbfd -lopcodes -liberty -lz
     endif
   endif
 endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (10 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-18 16:38   ` Arnaldo Carvalho de Melo
                     ` (3 more replies)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
                   ` (4 subsequent siblings)
  16 siblings, 4 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch enables the annotation of bpf program.

A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
calls into a new function symbol__disassemble_bpf(), where annotation
line information is filled based bpf_prog_info and btf saved in given
perf_env.

symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/build/Makefile.feature |   6 +-
 tools/perf/Makefile.config   |   4 +
 tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
 tools/perf/util/dso.c        |   1 +
 tools/perf/util/dso.h        |  32 +++++---
 tools/perf/util/symbol.c     |   1 +
 6 files changed, 180 insertions(+), 14 deletions(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 61e46d54a67c..8d3864b061f3 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
         sched_getcpu			\
         sdt				\
         setns				\
-        libaio
+        libaio				\
+        disassembler-four-args
 
 # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
 # of all feature tests
@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
          lzma                   \
          get_cpuid              \
          bpf			\
-         libaio
+         libaio			\
+         disassembler-four-args
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index df4ad45599ca..c51b59e43dcc 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq ($(feature-disassembler-four-args), 1)
+    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
+endif
+
 ifeq (${IS_64_BIT}, 1)
   ifndef NO_PERF_READ_VDSO32
     $(call feature_check,compile-32)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 5f6dbbf5d749..e492b19a157c 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -10,6 +10,10 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <libgen.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
 #include "util.h"
 #include "ui/ui.h"
 #include "sort.h"
@@ -24,6 +28,7 @@
 #include "annotate.h"
 #include "evsel.h"
 #include "evlist.h"
+#include "bpf-event.h"
 #include "block-range.h"
 #include "string2.h"
 #include "arch/common.h"
@@ -31,6 +36,9 @@
 #include <pthread.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
+#include <bfd.h>
+#include <dis-asm.h>
+#include <bpf/libbpf.h>
 
 /* FIXME: For the HE_COLORSET */
 #include "ui/browser.h"
@@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
 	return 0;
 }
 
+static int symbol__disassemble_bpf(struct symbol *sym,
+				   struct annotate_args *args)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct annotation_options *opts = args->options;
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_linfo *prog_linfo = NULL;
+	struct bpf_prog_info_node *info_node;
+	int len = sym->end - sym->start;
+	disassembler_ftype disassemble;
+	struct map *map = args->ms.map;
+	struct disassemble_info info;
+	struct dso *dso = map->dso;
+	int pc = 0, count, sub_id;
+	struct btf *btf = NULL;
+	char tpath[PATH_MAX];
+	size_t buf_size;
+	int nr_skip = 0;
+	int ret = -1;
+	char *buf;
+	bfd *bfdf;
+	FILE *s;
+
+	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
+		return -1;
+
+	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
+		 sym->name, sym->start, sym->end - sym->start);
+
+	memset(tpath, 0, sizeof(tpath));
+	perf_exe(tpath, sizeof(tpath));
+
+	bfdf = bfd_openr(tpath, NULL);
+	assert(bfdf);
+	assert(bfd_check_format(bfdf, bfd_object));
+
+	s = open_memstream(&buf, &buf_size);
+	if (!s)
+		goto out;
+	init_disassemble_info(&info, s,
+			      (fprintf_ftype) fprintf);
+
+	info.arch = bfd_get_arch(bfdf);
+	info.mach = bfd_get_mach(bfdf);
+
+	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
+						 dso->bpf_prog.id);
+	if (!info_node)
+		goto out;
+	info_linear = info_node->info_linear;
+	sub_id = dso->bpf_prog.sub_id;
+
+	info.buffer = (void *)(info_linear->info.jited_prog_insns);
+	info.buffer_length = info_linear->info.jited_prog_len;
+
+	if (info_linear->info.nr_line_info)
+		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
+
+	if (info_linear->info.btf_id) {
+		struct btf_node *node;
+
+		node = perf_env__find_btf(dso->bpf_prog.env,
+					  info_linear->info.btf_id);
+		if (node)
+			btf = btf__new((__u8 *)(node->data),
+				       node->data_size);
+	}
+
+	disassemble_init_for_target(&info);
+
+#ifdef DISASM_FOUR_ARGS_SIGNATURE
+	disassemble = disassembler(info.arch,
+				   bfd_big_endian(bfdf),
+				   info.mach,
+				   bfdf);
+#else
+	disassemble = disassembler(bfdf);
+#endif
+	assert(disassemble);
+
+	fflush(s);
+	do {
+		const struct bpf_line_info *linfo = NULL;
+		struct disasm_line *dl;
+		size_t prev_buf_size;
+		const char *srcline;
+		u64 addr;
+
+		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
+		count = disassemble(pc, &info);
+
+		if (prog_linfo)
+			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
+								addr, sub_id,
+								nr_skip);
+
+		if (linfo && btf) {
+			srcline = btf__name_by_offset(btf, linfo->line_off);
+			nr_skip++;
+		} else
+			srcline = NULL;
+
+		fprintf(s, "\n");
+		prev_buf_size = buf_size;
+		fflush(s);
+
+		if (!opts->hide_src_code && srcline) {
+			args->offset = -1;
+			args->line = strdup(srcline);
+			args->line_nr = 0;
+			args->ms.sym  = sym;
+			dl = disasm_line__new(args);
+			if (dl) {
+				annotation_line__add(&dl->al,
+						     &notes->src->source);
+			}
+		}
+
+		args->offset = pc;
+		args->line = buf + prev_buf_size;
+		args->line_nr = 0;
+		args->ms.sym  = sym;
+		dl = disasm_line__new(args);
+		if (dl)
+			annotation_line__add(&dl->al, &notes->src->source);
+
+		pc += count;
+	} while (count > 0 && pc < len);
+
+	ret = 0;
+out:
+	free(prog_linfo);
+	free(btf);
+	fclose(s);
+	bfd_close(bfdf);
+	return ret;
+}
+
 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 {
 	struct annotation_options *opts = args->options;
@@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
 		 dso, dso->long_name, sym, sym->name);
 
-	if (dso__is_kcore(dso)) {
+	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+		return symbol__disassemble_bpf(sym, args);
+	} else if (dso__is_kcore(dso)) {
 		kce.kcore_filename = symfs_filename;
 		kce.addr = map__rip_2objdump(map, sym->start);
 		kce.offs = sym->start;
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index ba58ba603b69..58547c468c65 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	case DSO_BINARY_TYPE__KALLSYMS:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
 	case DSO_BINARY_TYPE__JAVA_JIT:
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
 		break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index bb417c54c25a..c274b5aa839d 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,7 @@
 
 struct machine;
 struct map;
+struct perf_env;
 
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -35,6 +36,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BPF_PROG_INFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
@@ -178,17 +180,25 @@ struct dso {
 	struct auxtrace_cache *auxtrace_cache;
 	int		 comp;
 
-	/* dso data file */
-	struct {
-		struct rb_root	 cache;
-		int		 fd;
-		int		 status;
-		u32		 status_seen;
-		size_t		 file_size;
-		struct list_head open_entry;
-		u64		 debug_frame_offset;
-		u64		 eh_frame_hdr_offset;
-	} data;
+	union {
+		/* dso data file */
+		struct {
+			struct rb_root	 cache;
+			int		 fd;
+			int		 status;
+			u32		 status_seen;
+			size_t		 file_size;
+			struct list_head open_entry;
+			u64		 debug_frame_offset;
+			u64		 eh_frame_hdr_offset;
+		} data;
+		/* bpf prog information */
+		struct {
+			u32		id;
+			u32		sub_id;
+			struct perf_env	*env;
+		} bpf_prog;
+	};
 
 	union { /* Tool specific area */
 		void	 *priv;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 758bf5f74e6e..4e2e304d4037 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
 		return true;
 
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 	default:
 		return false;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (11 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:43   ` [tip:perf/urgent] perf bpf: Process " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 14/15] perf: introduce side band thread Song Liu
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch adds processing of PERF_BPF_EVENT_PROG_LOAD, which sets proper
DSO type/id/etc of memory regions mapped to BPF programs to
DSO_BINARY_TYPE__BPF_PROG_INFO

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/util/bpf-event.c | 54 +++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index e02a38a98d8d..af434de3a23e 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -12,6 +12,7 @@
 #include "machine.h"
 #include "env.h"
 #include "session.h"
+#include "map.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -25,12 +26,65 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
 	return ret;
 }
 
+static int machine__process_bpf_event_load(struct machine *machine,
+					   union perf_event *event,
+					   struct perf_sample *sample __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = machine->env;
+	int id = event->bpf_event.id;
+	unsigned int i;
+
+	/* perf-record, no need to handle bpf-event */
+	if (env == NULL)
+		return 0;
+
+	info_node = perf_env__find_bpf_prog_info(env, id);
+	if (!info_node)
+		return 0;
+	info_linear = info_node->info_linear;
+
+	for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
+		u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
+		u64 addr = addrs[i];
+		struct map *map;
+
+		map = map_groups__find(&machine->kmaps, addr);
+
+		if (map) {
+			map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
+			map->dso->bpf_prog.id = id;
+			map->dso->bpf_prog.sub_id = i;
+			map->dso->bpf_prog.env = env;
+		}
+	}
+	return 0;
+}
+
 int machine__process_bpf_event(struct machine *machine __maybe_unused,
 			       union perf_event *event,
 			       struct perf_sample *sample __maybe_unused)
 {
 	if (dump_trace)
 		perf_event__fprintf_bpf_event(event, stdout);
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		return machine__process_bpf_event_load(machine, event, sample);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
 	return 0;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 14/15] perf: introduce side band thread
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (12 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-22 22:45   ` [tip:perf/urgent] perf evlist: Introduce " tip-bot for Song Liu
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

This patch introduces side band thread that captures extended information
for events like PERF_RECORD_BPF_EVENT.

This new thread uses its own evlist that uses ring buffer with very low
watermark for lower latency.

To use side band thread, we need to:

1. add side band event(s) by calling perf_evlist__add_sb_event();
2. calls perf_evlist__start_sb_thread();
3. at the end of perf run, perf_evlist__stop_sb_thread().

In the next patch, we use this thread to handle PERF_RECORD_BPF_EVENT.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/builtin-record.c |   5 ++
 tools/perf/builtin-top.c    |   5 ++
 tools/perf/util/evlist.c    | 119 ++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h    |  12 ++++
 tools/perf/util/evsel.h     |   6 ++
 5 files changed, 147 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2d34039c4246..f792dd28d936 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1116,6 +1116,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	struct perf_data *data = &rec->data;
 	struct perf_session *session;
 	bool disabled = false, draining = false;
+	struct perf_evlist *sb_evlist = NULL;
 	int fd;
 
 	atexit(record__sig_exit);
@@ -1216,6 +1217,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
+
 	err = record__synthesize(rec, false);
 	if (err < 0)
 		goto out_child;
@@ -1466,6 +1469,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 out_delete_session:
 	perf_session__delete(session);
+
+	perf_evlist__stop_sb_thread(sb_evlist);
 	return status;
 }
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 63a8f686c5cb..9577dba4996b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1512,6 +1512,7 @@ int cmd_top(int argc, const char **argv)
 			"number of thread to run event synthesize"),
 	OPT_END()
 	};
+	struct perf_evlist *sb_evlist = NULL;
 	const char * const top_usage[] = {
 		"perf top [<options>]",
 		NULL
@@ -1640,8 +1641,12 @@ int cmd_top(int argc, const char **argv)
 		signal(SIGWINCH, winch_sig);
 	}
 
+	perf_evlist__start_sb_thread(sb_evlist, target);
+
 	status = __cmd_top(&top);
 
+	perf_evlist__stop_sb_thread(sb_evlist);
+
 out_delete_evlist:
 	perf_evlist__delete(top.evlist);
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ed20f4379956..ec78e93085de 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@
 #include "debug.h"
 #include "units.h"
 #include "asm/bug.h"
+#include "bpf-event.h"
 #include <signal.h>
 #include <unistd.h>
 
@@ -1856,3 +1857,121 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
 	}
 	return leader;
 }
+
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data)
+{
+	struct perf_evsel *evsel;
+	bool new_evlist = (*evlist) == NULL;
+
+	if (*evlist == NULL)
+		*evlist = perf_evlist__new();
+	if (*evlist == NULL)
+		return -1;
+
+	if (!attr->sample_id_all) {
+		pr_warning("enabling sample_id_all for all side band events\n");
+		attr->sample_id_all = 1;
+	}
+
+	evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries);
+	if (!evsel)
+		goto out_err;
+
+	evsel->side_band.cb = cb;
+	evsel->side_band.data = data;
+	perf_evlist__add(*evlist, evsel);
+	return 0;
+
+out_err:
+	if (new_evlist) {
+		perf_evlist__delete(*evlist);
+		*evlist = NULL;
+	}
+	return -1;
+}
+
+static void *perf_evlist__poll_thread(void *arg)
+{
+	struct perf_evlist *evlist = arg;
+	bool draining = false;
+	int i;
+
+	while (draining || !(evlist->thread.done)) {
+		if (draining)
+			draining = false;
+		else if (evlist->thread.done)
+			draining = true;
+
+		if (!draining)
+			perf_evlist__poll(evlist, 1000);
+
+		for (i = 0; i < evlist->nr_mmaps; i++) {
+			struct perf_mmap *map = &evlist->mmap[i];
+			union perf_event *event;
+
+			if (perf_mmap__read_init(map))
+				continue;
+			while ((event = perf_mmap__read_event(map)) != NULL) {
+				struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
+
+				if (evsel && evsel->side_band.cb)
+					evsel->side_band.cb(event, evsel->side_band.data);
+				else
+					pr_warning("cannot locate proper evsel for the side band event\n");
+
+				perf_mmap__consume(map);
+			}
+			perf_mmap__read_done(map);
+		}
+	}
+	return NULL;
+}
+
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target)
+{
+	struct perf_evsel *counter;
+
+	if (!evlist)
+		return 0;
+
+	if (perf_evlist__create_maps(evlist, target))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__open(counter, evlist->cpus,
+				     evlist->threads) < 0)
+			goto out_delete_evlist;
+	}
+
+	if (perf_evlist__mmap(evlist, UINT_MAX))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__enable(counter))
+			goto out_delete_evlist;
+	}
+
+	evlist->thread.done = 0;
+	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
+		goto out_delete_evlist;
+
+	return 0;
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	evlist = NULL;
+	return -1;
+}
+
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
+{
+	if (!evlist)
+		return;
+	evlist->thread.done = 1;
+	pthread_join(evlist->thread.th, NULL);
+	perf_evlist__delete(evlist);
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 744906dd4887..dcb68f34d2cd 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,10 @@ struct perf_evlist {
 				       struct perf_sample *sample);
 	u64		first_sample_time;
 	u64		last_sample_time;
+	struct {
+		pthread_t		th;
+		volatile int		done;
+	} thread;
 };
 
 struct perf_evsel_str_handler {
@@ -87,6 +91,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
 
 int perf_evlist__add_dummy(struct perf_evlist *evlist);
 
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data);
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target);
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist);
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
 			   const char *sys, const char *name, void *handler);
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index cc578e02e08f..0f2c6c93d721 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -73,6 +73,8 @@ struct perf_evsel_config_term {
 
 struct perf_stat_evsel;
 
+typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);
+
 /** struct perf_evsel - event selector
  *
  * @evlist - evlist this evsel is in, if it is in one.
@@ -151,6 +153,10 @@ struct perf_evsel {
 	bool			collect_stat;
 	bool			weak_group;
 	const char		*pmu_name;
+	struct {
+		perf_evsel__sb_cb_t	*cb;
+		void			*data;
+	} side_band;
 };
 
 union u64_swap {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (13 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 14/15] perf: introduce side band thread Song Liu
@ 2019-03-12  5:30 ` Song Liu
  2019-03-19 15:25   ` Arnaldo Carvalho de Melo
  2019-03-22 22:45   ` [tip:perf/urgent] perf tools: Save bpf_prog_info and BTF of new BPF programs tip-bot for Song Liu
  2019-03-12 13:12 ` [PATCH v9 perf,bpf 00/15] perf annotation of " Jiri Olsa
  2019-03-21  9:10 ` Jiri Olsa
  16 siblings, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-12  5:30 UTC (permalink / raw)
  To: bpf, netdev, linux-kernel
  Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, sdf, Song Liu

To fully annotate BPF programs with source code mapping, 4 different
information are needed:
    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

This patch handles 3) and 4) for short living BPF programs. For timely
process of these information, a dedicated event is added to the side
band evlist. When PERF_RECORD_BPF_EVENT is received via the side band
event, the polling thread gathers 3) and 4) vis sys_bpf and store them
in perf_env. These information are saved to perf.data at the end of
perf-record.

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

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f792dd28d936..3c0596a68992 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1217,6 +1217,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	if (!opts->no_bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
 	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
 
 	err = record__synthesize(rec, false);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 9577dba4996b..b7790d66cac2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1641,6 +1641,8 @@ int cmd_top(int argc, const char **argv)
 		signal(SIGWINCH, winch_sig);
 	}
 
+	if (!top.record_opts.no_bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &perf_env);
 	perf_evlist__start_sb_thread(sb_evlist, target);
 
 	status = __cmd_top(&top);
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index af434de3a23e..77e0fdead6f4 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -13,6 +13,7 @@
 #include "env.h"
 #include "session.h"
 #include "map.h"
+#include "evlist.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -330,3 +331,97 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 	free(event);
 	return err;
 }
+
+static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct btf *btf = NULL;
+	u64 arrays;
+	u32 btf_id;
+	int fd;
+
+	fd = bpf_prog_get_fd_by_id(id);
+	if (fd < 0)
+		return;
+
+	arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
+	arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
+	arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
+
+	info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+	if (IS_ERR_OR_NULL(info_linear)) {
+		pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
+		goto out;
+	}
+
+	btf_id = info_linear->info.btf_id;
+
+	info_node = malloc(sizeof(struct bpf_prog_info_node));
+	if (info_node) {
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	} else
+		free(info_linear);
+
+	if (btf_id == 0)
+		goto out;
+
+	if (btf__get_from_id(btf_id, &btf)) {
+		pr_debug("%s: failed to get BTF of id %u, aborting\n",
+			 __func__, btf_id);
+		goto out;
+	}
+	perf_env__fetch_btf(env, btf_id, btf);
+
+out:
+	free(btf);
+	close(fd);
+}
+
+static int bpf_event__sb_cb(union perf_event *event, void *data)
+{
+	struct perf_env *env = data;
+
+	if (event->header.type != PERF_RECORD_BPF_EVENT)
+		return -1;
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		perf_env__add_bpf_info(env, event->bpf_event.id);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
+
+	return 0;
+}
+
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+			    struct perf_env *env)
+{
+	struct perf_event_attr attr = {
+		.type	          = PERF_TYPE_SOFTWARE,
+		.config           = PERF_COUNT_SW_DUMMY,
+		.sample_id_all    = 1,
+		.watermark        = 1,
+		.bpf_event        = 1,
+		.wakeup_watermark = 1,
+		.size	   = sizeof(attr), /* to capture ABI version */
+	};
+
+	return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
+}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index b9ec394dc7c7..249909c826e7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -4,12 +4,17 @@
 
 #include <linux/compiler.h>
 #include <linux/rbtree.h>
+#include <pthread.h>
+#include <api/fd/array.h>
 #include "event.h"
 
 struct machine;
 union perf_event;
+struct perf_env;
 struct perf_sample;
 struct record_opts;
+struct evlist;
+struct target;
 
 struct bpf_prog_info_node {
 	struct bpf_prog_info_linear	*info_linear;
@@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 				      perf_event__handler_t process,
 				      struct machine *machine,
 				      struct record_opts *opts);
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+				 struct perf_env *env);
+
 #else
 static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
 					     union perf_event *event __maybe_unused,
@@ -46,5 +54,12 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
 {
 	return 0;
 }
+
+static int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
+				   struct perf_env *env __maybe_unused)
+{
+	return 0;
+}
+
 #endif // HAVE_LIBBPF_SUPPORT
 #endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-11 20:57       ` Arnaldo Carvalho de Melo
@ 2019-03-12 11:20         ` Daniel Borkmann
  0 siblings, 0 replies; 100+ messages in thread
From: Daniel Borkmann @ 2019-03-12 11:20 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Alexei Starovoitov, Song Liu, bpf, netdev, linux-kernel, ast,
	kernel-team, peterz, acme, jolsa, namhyung

On 03/11/2019 09:57 PM, Arnaldo Carvalho de Melo wrote:
> Em Mon, Mar 11, 2019 at 09:45:49PM +0100, Daniel Borkmann escreveu:
>> On 03/11/2019 07:26 PM, Arnaldo Carvalho de Melo wrote:
>>> Em Thu, Mar 07, 2019 at 09:57:57AM -0800, Song Liu escreveu:
>>>> Currently, bpf_prog_info includes 9 arrays. The user has the option to
>>>> fetch any combination of these arrays. However, this requires a lot of
>>>> handling of these arrays. This work becomes more tricky when we need to
>>>> store bpf_prog_info to a file, because these arrays are allocated
>>>> independently.
>>>>
>>>> This patch introduces struct bpf_prog_info_linear, which stores arrays
>>>> of bpf_prog_info in continues memory. Helper functions are introduced
>>>> to unify the work to get different information of bpf_prog_info.
>>>> Specifically, bpf_program__get_prog_info_linear() allows the user to
>>>> select which arrays to fetch, and handles details for the user.
>>>>
>>>> Plesae see the comments before enum bpf_prog_info_array for more details
>>>> and examples.
>>>>
>>>> Cc: Daniel Borkmann <daniel@iogearbox.net>
>>>> Cc: Alexei Starovoitov <ast@kernel.org>
>>>
>>> Daniel, are you ok with these changes to libbpf and bpftool? Perhaps
>>> those should be detached from this patchkit and submitted sooner,
>>> eroding the size of this kit.
>>>
>>> Alternatively, if you're ok with it, please provide your Acked-by and
>>> I'll process as soon as I get back to it after Jiri is done reviewing.
>>
>> Overall looks okay. Are you planning to get these in for 5.1 window? If
> 
> I hope so.
> 
>> yes, that would be great, otherwise we might need to cherry-pick the libbpf
> 
> So I'll try and grab those for my next pull req to Ingo, this week,
> will add your Acked-by, ok?

Please do, thanks.

>> and bpftool ones from your tree into bpf-next as well since there's just
>> too much going on in this area where we'd potentially run into complex
>> merge conflicts. In the latter case, libbpf.map would need to be fixed up
>> to LIBBPF_0.0.3 as convention is that this is in line with kernel release.
> 
> BTW, while running my build tests I had to add this to today's batch,
> should be trivial when merging, I think, ok?

That's fine as well, ack, lets shoot for getting it in during merge window
such that we don't need to duplicate these dependencies in bpf trees.

> commit dfcbc2f2994b8a3af3605a26dc29c07ad7378bf4
> Author: Arnaldo Carvalho de Melo <acme@redhat.com>
> Date:   Mon Mar 11 17:07:52 2019 -0300
> 
>     tools lib bpf: Fix the build by adding a missing stdarg.h include
>     
>     The libbpf_print_fn_t typedef uses va_list without including the header
>     where that type is defined, stdarg.h, breaking in places where we're
>     unlucky for that type not to be already defined by some previously
>     included header.
>     
>     Noticed while building on fedora 24 cross building tools/perf to the ARC
>     architecture using the uClibc C library:
>     
>       28 fedora:24-x-ARC-uClibc   : FAIL arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710
>     
>         CC       /tmp/build/perf/tests/llvm.o
>       In file included from tests/llvm.c:3:0:
>       /git/linux/tools/lib/bpf/libbpf.h:57:20: error: unknown type name 'va_list'
>             const char *, va_list ap);
>                           ^~~~~~~
>       /git/linux/tools/lib/bpf/libbpf.h:59:34: error: unknown type name 'libbpf_print_fn_t'
>        LIBBPF_API void libbpf_set_print(libbpf_print_fn_t fn);
>                                         ^~~~~~~~~~~~~~~~~
>       mv: cannot stat '/tmp/build/perf/tests/.llvm.o.tmp': No such file or directory
>     
>     Cc: Alexei Starovoitov <ast@kernel.org>
>     Cc: Daniel Borkmann <daniel@iogearbox.net>
>     Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
>     Cc: Jiri Olsa <jolsa@kernel.org>
>     Cc: Namhyung Kim <namhyung@kernel.org>
>     Cc: Quentin Monnet <quentin.monnet@netronome.com>
>     Cc: Stanislav Fomichev <sdf@google.com>
>     Cc: Yonghong Song <yhs@fb.com>
>     Fixes: a8a1f7d09cfc ("libbpf: fix libbpf_print")
>     Link: https://lkml.kernel.org/n/tip-5270n2quu2gqz22o7itfdx00@git.kernel.org
>     Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> 
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index b4652aa1a58a..aa1521a51687 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -10,6 +10,7 @@
>  #ifndef __LIBBPF_LIBBPF_H
>  #define __LIBBPF_LIBBPF_H
>  
> +#include <stdarg.h>
>  #include <stdio.h>
>  #include <stdint.h>
>  #include <stdbool.h>
> 

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
@ 2019-03-12 13:10   ` Jiri Olsa
  2019-03-12 14:47     ` Arnaldo Carvalho de Melo
  2019-03-13 19:05   ` Arnaldo Carvalho de Melo
  2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
  2 siblings, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-12 13:10 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

On Mon, Mar 11, 2019 at 10:30:43PM -0700, Song Liu wrote:

SNIP

> +static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
> +{
> +	struct perf_env *env = &ff->ph->env;
> +	struct rb_root *root;
> +	struct rb_node *next;
> +
> +	down_read(&env->bpf_progs.lock);
> +
> +	root = &env->bpf_progs.infos;
> +	next = rb_first(root);
> +
> +	while (next) {
> +		struct bpf_prog_info_node *node;
> +
> +		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
> +		next = rb_next(&node->rb_node);
> +		fprintf(fp, "# bpf_prog_info of id %u\n",
> +			node->info_linear->info.id);

so report displays bpf prog dso/name like:

   0.02%  ls           bpf_prog_c80ffe554aba1bec_syscall_enter_o  [k] bpf_prog_c80ffe554aba1bec_syscall_enter_o                                                                                       ▒

and 'perf report --header-only -I' shows:


	# bpf_prog_info of id 17
	# bpf_prog_info of id 18
	# bpf_prog_info of id 19
	# bpf_prog_info of id 20
	# bpf_prog_info of id 21
	# bpf_prog_info of id 22
	# bpf_prog_info of id 25
	# bpf_prog_info of id 26
	# bpf_prog_info of id 34
	# bpf_prog_info of id 35

could we have something more detailed like bpftool output:

	34: tracepoint  name syscall_enter_o  tag c80ffe554aba1bec  gpl
		loaded_at 2019-03-12T14:02:03+0100  uid 0
		xlated 360B  jited 232B  memlock 4096B  map_ids 30

	35: tracepoint  name syscall_enter_o  tag ada5ccbe5576399c  gpl
		loaded_at 2019-03-12T14:02:03+0100  uid 0
		xlated 352B  jited 228B  memlock 4096B  map_ids 30


could be on top of this patchset

jirka

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
@ 2019-03-12 13:10   ` Jiri Olsa
  2019-03-12 14:34     ` Arnaldo Carvalho de Melo
  2019-03-22 22:38   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
  1 sibling, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-12 13:10 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

On Mon, Mar 11, 2019 at 10:30:42PM -0700, Song Liu wrote:

SNIP

> +/* purge data in bpf_progs.infos tree */
> +static void perf_env__purge_bpf(struct perf_env *env)
> +{
> +	struct rb_root *root;
> +	struct rb_node *next;
> +
> +	down_write(&env->bpf_progs.lock);
> +
> +	root = &env->bpf_progs.infos;
> +	next = rb_first(root);
> +
> +	while (next) {
> +		struct bpf_prog_info_node *node;
> +
> +		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
> +		next = rb_next(&node->rb_node);
> +		rb_erase(&node->rb_node, root);
> +		free(node);
> +	}

	env->bpf_progs.infos_cnt = 0;  ?

but it's probably not needed given the current usage

jirka

> +	up_write(&env->bpf_progs.lock);
> +}

SNIP

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (14 preceding siblings ...)
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
@ 2019-03-12 13:12 ` Jiri Olsa
  2019-03-21  9:10 ` Jiri Olsa
  16 siblings, 0 replies; 100+ messages in thread
From: Jiri Olsa @ 2019-03-12 13:12 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

On Mon, Mar 11, 2019 at 10:30:36PM -0700, Song Liu wrote:
> Changes v8 to v9:
> 1. Rebase on top of torvalds/master:
>     commit ea295481b6e313b4ea3ca2720ffcafd6005b5643 ;
> 2. Change perf-record option --bpf-event to --no-bpf-event.

Reviewed-by: Jiri Olsa <jolsa@kernel.org>

thanks for bearing with me ;-)

jirka


> 
> Changes v7 to v8:
> 1. Address issues suggested by Jiri and Stanislav.
> 
> Changes v6 to v7:
> 1. Fix minor issues suggested by Jiri.
> 
> Changes v5 to v6:
> 1. Improve side band evlist interface;
> 2. Minor style fixes.
> 
> Changes v4 to v5:
> 1. Rebase to latest bpf-next;
> 2. Add dependency of 94816add0005 from Arnaldo's tree;
> 3. More details in change logs;
> 4. Add perf_env__init() to init bpf related lock and rbtrees;
> 5. Small clean ups.
> 
> Changes v3 to v4:
> 1. Incorporate feedbacks from Jiri and Namhyung;
> 2. Fixed compilation error with different feature-disassembler-four-args;
> 3. Split some patches to smaller patches;
> 4. Improved error handleing in symbol__disassemble_bpf();
> 5. Made side band thread more generic;
> 6. Added comments as suggested.
> 
> Changes v2 to v3:
> 1. Remove unnecessary include in header files;
> 2. Improved error handling;
> 3. Better naming of functions, variables, etc.;
> 4. Enable bpf events by default for perf-top.
> 
> Changes v1 to v2:
> 1. Fix compilation error with different feature-disassembler-four-args;
> 2. Fix a segfault in perf-record;
> 3. Split patches 5/9 and 6/9 so that perf_env changes and perf.data changes
>    are in separate patches.
> 
> This series enables annotation of BPF programs in perf.
> 
> perf tool gathers information via sys_bpf and (optionally) stores them in
> perf.data as headers.
> 
> Patch 1/15 changes --bpf-event option to --no-bpf-event;
> Patch 2/15 to 4/15 introduce new helper functions and use them in perf and
>      bpftool;
> Patch 5/15 to 9/15 saves information of bpf program in perf_env;
> Patch 10/15 adds --bpf-event options to perf-top;
> Patch 11/15 to 13/15 enables annotation of bpf progs based on information
>      gathered in 5/15 to 9/15;
> Patch 14/15 introduces side band polling thread that gathers information
>      for special kernel events during perf-record or perf-top.
> Patch 15/15 handles information of short living BPF program using the new
>      side band polling thread.
> 
> Commands tested during developments are perf-top, perf-record, perf-report,
> and perf-annotate.
> 
> This set is also available at:
> 
> https://github.com/liu-song-6/linux/tree/bpf-annotation-v9
> 
> Thanks!!
> 
> Song Liu (15):
>   perf-record: replace option --bpf-event with --no-bpf-event
>   bpf: libbpf: introduce bpf_program__get_prog_info_linear()
>   bpf: bpftool: use bpf_program__get_prog_info_linear() in
>     prog.c:do_dump()
>   perf, bpf: synthesize bpf events with
>     bpf_program__get_prog_info_linear()
>   perf: change prototype of perf_event__synthesize_bpf_events()
>   perf, bpf: save bpf_prog_info in a rbtree in perf_env
>   perf, bpf: save bpf_prog_info information as headers to perf.data
>   perf, bpf: save btf in a rbtree in perf_env
>   perf, bpf: save btf information as headers to perf.data
>   perf-top: add option --no-bpf-event
>   perf: add -lopcodes to feature-libbfd
>   perf, bpf: enable annotation of bpf program
>   perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
>   perf: introduce side band thread
>   perf, bpf: save bpf_prog_info and btf of short living bpf programs
> 
>  tools/bpf/bpftool/prog.c     | 266 +++++++---------------------
>  tools/build/Makefile.feature |   6 +-
>  tools/lib/bpf/libbpf.c       | 251 ++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h       |  63 +++++++
>  tools/lib/bpf/libbpf.map     |   3 +
>  tools/perf/Makefile.config   |  10 +-
>  tools/perf/builtin-record.c  |  11 +-
>  tools/perf/builtin-top.c     |  10 +-
>  tools/perf/perf.c            |   1 +
>  tools/perf/perf.h            |   2 +-
>  tools/perf/util/annotate.c   | 150 +++++++++++++++-
>  tools/perf/util/bpf-event.c  | 330 ++++++++++++++++++++++++++---------
>  tools/perf/util/bpf-event.h  |  33 +++-
>  tools/perf/util/dso.c        |   1 +
>  tools/perf/util/dso.h        |  32 ++--
>  tools/perf/util/env.c        | 151 ++++++++++++++++
>  tools/perf/util/env.h        |  24 +++
>  tools/perf/util/evlist.c     | 119 +++++++++++++
>  tools/perf/util/evlist.h     |  12 ++
>  tools/perf/util/evsel.c      |   2 +-
>  tools/perf/util/evsel.h      |   6 +
>  tools/perf/util/header.c     | 238 ++++++++++++++++++++++++-
>  tools/perf/util/header.h     |   2 +
>  tools/perf/util/session.c    |   1 +
>  tools/perf/util/symbol.c     |   1 +
>  25 files changed, 1409 insertions(+), 316 deletions(-)
> 
> --
> 2.17.1

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-12 13:50   ` Arnaldo Carvalho de Melo
  2019-03-22 22:36   ` [tip:perf/urgent] tools lib bpf: Introduce bpf_program__get_prog_info_linear() tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 13:50 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:38PM -0700, Song Liu escreveu:
> Currently, bpf_prog_info includes 9 arrays. The user has the option to
> fetch any combination of these arrays. However, this requires a lot of
> handling of these arrays. This work becomes more tricky when we need to
> store bpf_prog_info to a file, because these arrays are allocated
> independently.
> 
> This patch introduces struct bpf_prog_info_linear, which stores arrays
> of bpf_prog_info in continues memory. Helper functions are introduced
> to unify the work to get different information of bpf_prog_info.
> Specifically, bpf_program__get_prog_info_linear() allows the user to
> select which arrays to fetch, and handles details for the user.
> 
> Plesae see the comments before enum bpf_prog_info_array for more details
> and examples.
> 
> Cc: Daniel Borkmann <daniel@iogearbox.net>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/lib/bpf/libbpf.c   | 251 +++++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h   |  63 ++++++++++
>  tools/lib/bpf/libbpf.map |   3 +
>  3 files changed, 317 insertions(+)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index d5b830d60601..98ec9a8cd7af 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
>  # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
>  #endif
>  
> +static inline __u64 ptr_to_u64(const void *ptr)
> +{
> +	return (__u64) (unsigned long) ptr;
> +}
> +
>  struct bpf_capabilities {
>  	/* v4.14: kernel support for program & map names. */
>  	__u32 name:1;
> @@ -2999,3 +3004,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
>  	ring_buffer_write_tail(header, data_tail);
>  	return ret;
>  }
> +
> +struct bpf_prog_info_array_desc {
> +	int	array_offset;	/* e.g. offset of jited_prog_insns */
> +	int	count_offset;	/* e.g. offset of jited_prog_len */
> +	int	size_offset;	/* > 0: offset of rec size,
> +				 * < 0: fix size of -size_offset
> +				 */
> +};
> +
> +static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
> +	[BPF_PROG_INFO_JITED_INSNS] = {
> +		offsetof(struct bpf_prog_info, jited_prog_insns),
> +		offsetof(struct bpf_prog_info, jited_prog_len),
> +		-1,
> +	},
> +	[BPF_PROG_INFO_XLATED_INSNS] = {
> +		offsetof(struct bpf_prog_info, xlated_prog_insns),
> +		offsetof(struct bpf_prog_info, xlated_prog_len),
> +		-1,
> +	},

Can be done on top, but this is too much boilerplate, later we can use
something like:

@define BPF_PROG_INFO_ENTRY(idx, array, count, offset) \
	[BPF_PROG_INFO ## index_name] = { \
		offsetof(struct bpf_prog_info, array), \ 
		offsetof(struct bpf_prog_info, count), \ 
		(int)offset \
	}

And then have a more compact

	static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
		BPF_PROG_INFO_ENTRY(JITED_INSNS, jited_prog_insns, jided_prog_len, -1 );
		BPF_PROG_INFO_ENTRY(MAP_IDS, map_ids, nr_map_ids, -sizeof(__u32));

	etc.

Anyway, processing it as-is for now.


> +	[BPF_PROG_INFO_MAP_IDS] = {
> +		offsetof(struct bpf_prog_info, map_ids),
> +		offsetof(struct bpf_prog_info, nr_map_ids),
> +		-(int)sizeof(__u32),
> +	},
> +	[BPF_PROG_INFO_JITED_KSYMS] = {
> +		offsetof(struct bpf_prog_info, jited_ksyms),
> +		offsetof(struct bpf_prog_info, nr_jited_ksyms),
> +		-(int)sizeof(__u64),
> +	},
> +	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
> +		offsetof(struct bpf_prog_info, jited_func_lens),
> +		offsetof(struct bpf_prog_info, nr_jited_func_lens),
> +		-(int)sizeof(__u32),
> +	},
> +	[BPF_PROG_INFO_FUNC_INFO] = {
> +		offsetof(struct bpf_prog_info, func_info),
> +		offsetof(struct bpf_prog_info, nr_func_info),
> +		offsetof(struct bpf_prog_info, func_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_LINE_INFO] = {
> +		offsetof(struct bpf_prog_info, line_info),
> +		offsetof(struct bpf_prog_info, nr_line_info),
> +		offsetof(struct bpf_prog_info, line_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_JITED_LINE_INFO] = {
> +		offsetof(struct bpf_prog_info, jited_line_info),
> +		offsetof(struct bpf_prog_info, nr_jited_line_info),
> +		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
> +	},
> +	[BPF_PROG_INFO_PROG_TAGS] = {
> +		offsetof(struct bpf_prog_info, prog_tags),
> +		offsetof(struct bpf_prog_info, nr_prog_tags),
> +		-(int)sizeof(__u8) * BPF_TAG_SIZE,
> +	},
> +
> +};
> +
> +static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
> +{
> +	__u32 *array = (__u32 *)info;
> +
> +	if (offset >= 0)
> +		return array[offset / sizeof(__u32)];
> +	return -(int)offset;
> +}
> +
> +static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
> +{
> +	__u64 *array = (__u64 *)info;
> +
> +	if (offset >= 0)
> +		return array[offset / sizeof(__u64)];
> +	return -(int)offset;
> +}
> +
> +static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
> +					 __u32 val)
> +{
> +	__u32 *array = (__u32 *)info;
> +
> +	if (offset >= 0)
> +		array[offset / sizeof(__u32)] = val;
> +}
> +
> +static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
> +					 __u64 val)
> +{
> +	__u64 *array = (__u64 *)info;
> +
> +	if (offset >= 0)
> +		array[offset / sizeof(__u64)] = val;
> +}
> +
> +struct bpf_prog_info_linear *
> +bpf_program__get_prog_info_linear(int fd, __u64 arrays)
> +{
> +	struct bpf_prog_info_linear *info_linear;
> +	struct bpf_prog_info info = {};
> +	__u32 info_len = sizeof(info);
> +	__u32 data_len = 0;
> +	int i, err;
> +	void *ptr;
> +
> +	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* step 1: get array dimensions */
> +	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
> +	if (err) {
> +		pr_debug("can't get prog info: %s", strerror(errno));
> +		return ERR_PTR(-EFAULT);
> +	}
> +
> +	/* step 2: calculate total size of all arrays */
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		bool include_array = (arrays & (1UL << i)) > 0;
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 count, size;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +
> +		/* kernel is too old to support this field */
> +		if (info_len < desc->array_offset + sizeof(__u32) ||
> +		    info_len < desc->count_offset + sizeof(__u32) ||
> +		    (desc->size_offset > 0 && info_len < desc->size_offset))
> +			include_array = false;
> +
> +		if (!include_array) {
> +			arrays &= ~(1UL << i);	/* clear the bit */
> +			continue;
> +		}
> +
> +		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +
> +		data_len += count * size;
> +	}
> +
> +	/* step 3: allocate continuous memory */
> +	data_len = roundup(data_len, sizeof(__u64));
> +	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
> +	if (!info_linear)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* step 4: fill data to info_linear->info */
> +	info_linear->arrays = arrays;
> +	memset(&info_linear->info, 0, sizeof(info));
> +	ptr = info_linear->data;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 count, size;
> +
> +		if ((arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +		bpf_prog_info_set_offset_u32(&info_linear->info,
> +					     desc->count_offset, count);
> +		bpf_prog_info_set_offset_u32(&info_linear->info,
> +					     desc->size_offset, size);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset,
> +					     ptr_to_u64(ptr));
> +		ptr += count * size;
> +	}
> +
> +	/* step 5: call syscall again to get required arrays */
> +	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
> +	if (err) {
> +		pr_debug("can't get prog info: %s", strerror(errno));
> +		free(info_linear);
> +		return ERR_PTR(-EFAULT);
> +	}
> +
> +	/* step 6: verify the data */
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u32 v1, v2;
> +
> +		if ((arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
> +		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
> +						   desc->count_offset);
> +		if (v1 != v2)
> +			pr_warning("%s: mismatch in element count\n", __func__);
> +
> +		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
> +		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
> +						   desc->size_offset);
> +		if (v1 != v2)
> +			pr_warning("%s: mismatch in rec size\n", __func__);
> +	}
> +
> +	/* step 7: update info_len and data_len */
> +	info_linear->info_len = sizeof(struct bpf_prog_info);
> +	info_linear->data_len = data_len;
> +
> +	return info_linear;
> +}
> +
> +void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
> +{
> +	int i;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u64 addr, offs;
> +
> +		if ((info_linear->arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
> +						     desc->array_offset);
> +		offs = addr - ptr_to_u64(info_linear->data);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset, offs);
> +	}
> +}
> +
> +void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
> +{
> +	int i;
> +
> +	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
> +		struct bpf_prog_info_array_desc *desc;
> +		__u64 addr, offs;
> +
> +		if ((info_linear->arrays & (1UL << i)) == 0)
> +			continue;
> +
> +		desc = bpf_prog_info_array_desc + i;
> +		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
> +						     desc->array_offset);
> +		addr = offs + ptr_to_u64(info_linear->data);
> +		bpf_prog_info_set_offset_u64(&info_linear->info,
> +					     desc->array_offset, addr);
> +	}
> +}
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index b4652aa1a58a..c7645a5e1ac0 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -377,6 +377,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
>  LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
>  				 enum bpf_prog_type prog_type, __u32 ifindex);
>  
> +/*
> + * Get bpf_prog_info in continuous memory
> + *
> + * struct bpf_prog_info has multiple arrays. The user has option to choose
> + * arrays to fetch from kernel. The following APIs provide uniform way to
> + * fetch these data. All arrays in bpf_prog_info are stored in singile
> + * continuous memory region. This makes it easy to store the info in a
> + * file.
> + *
> + * Before writing bpf_prog_info_linear to files, it is necessary to
> + * translate pointers bpf_prog_info to offsets. Helper functions
> + * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
> + * are introduced to switch between pointers and offsets.
> + *
> + * Examples:
> + *   # To fetch map_ids and prog_tags:
> + *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
> + *           (1UL << BPF_PROG_INFO_PROG_TAGS);
> + *   struct bpf_prog_info_linear *info_linear =
> + *           bpf_program__get_prog_info_linear(fd, arrays);
> + *
> + *   # To save data in file
> + *   bpf_program__bpil_addr_to_offs(info_linear);
> + *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
> + *
> + *   # To read data from file
> + *   read(f, info_linear, <proper_size>);
> + *   bpf_program__bpil_offs_to_addr(info_linear);
> + */
> +enum bpf_prog_info_array {
> +	BPF_PROG_INFO_FIRST_ARRAY = 0,
> +	BPF_PROG_INFO_JITED_INSNS = 0,
> +	BPF_PROG_INFO_XLATED_INSNS,
> +	BPF_PROG_INFO_MAP_IDS,
> +	BPF_PROG_INFO_JITED_KSYMS,
> +	BPF_PROG_INFO_JITED_FUNC_LENS,
> +	BPF_PROG_INFO_FUNC_INFO,
> +	BPF_PROG_INFO_LINE_INFO,
> +	BPF_PROG_INFO_JITED_LINE_INFO,
> +	BPF_PROG_INFO_PROG_TAGS,
> +	BPF_PROG_INFO_LAST_ARRAY,
> +};
> +
> +struct bpf_prog_info_linear {
> +	/* size of struct bpf_prog_info, when the tool is compiled */
> +	__u32			info_len;
> +	/* total bytes allocated for data, round up to 8 bytes */
> +	__u32			data_len;
> +	/* which arrays are included in data */
> +	__u64			arrays;
> +	struct bpf_prog_info	info;
> +	__u8			data[];
> +};
> +
> +LIBBPF_API struct bpf_prog_info_linear *
> +bpf_program__get_prog_info_linear(int fd, __u64 arrays);
> +
> +LIBBPF_API void
> +bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
> +
> +LIBBPF_API void
> +bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
> +
>  #ifdef __cplusplus
>  } /* extern "C" */
>  #endif
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 778a26702a70..f3ce50500cf2 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
>  		xsk_socket__delete;
>  		xsk_umem__fd;
>  		xsk_socket__fd;
> +		bpf_program__get_prog_info_linear;
> +		bpf_program__bpil_addr_to_offs;
> +		bpf_program__bpil_offs_to_addr;
>  } LIBBPF_0.0.1;
> -- 
> 2.17.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env
  2019-03-12 13:10   ` Jiri Olsa
@ 2019-03-12 14:34     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 14:34 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Song Liu, bpf, netdev, linux-kernel, ast, daniel, kernel-team,
	peterz, acme, jolsa, namhyung, sdf, Andi Kleen

Em Tue, Mar 12, 2019 at 02:10:33PM +0100, Jiri Olsa escreveu:
> On Mon, Mar 11, 2019 at 10:30:42PM -0700, Song Liu wrote:
> 
> SNIP
> 
> > +/* purge data in bpf_progs.infos tree */
> > +static void perf_env__purge_bpf(struct perf_env *env)
> > +{
> > +	struct rb_root *root;
> > +	struct rb_node *next;
> > +
> > +	down_write(&env->bpf_progs.lock);
> > +
> > +	root = &env->bpf_progs.infos;
> > +	next = rb_first(root);
> > +
> > +	while (next) {
> > +		struct bpf_prog_info_node *node;
> > +
> > +		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
> > +		next = rb_next(&node->rb_node);
> > +		rb_erase(&node->rb_node, root);
> > +		free(node);
> > +	}
> 
> 	env->bpf_progs.infos_cnt = 0;  ?
> 
> but it's probably not needed given the current usage

Better be safe than sorry, see the Andi's "perf, tools, stat: Avoid
memory overrun with -r" :-)

I'll add the infos_cnt = 0 here.
 
> jirka
> 
> > +	up_write(&env->bpf_progs.lock);
> > +}
> 
> SNIP

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-12 13:10   ` Jiri Olsa
@ 2019-03-12 14:47     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 14:47 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Song Liu, bpf, netdev, linux-kernel, ast, daniel, kernel-team,
	peterz, acme, jolsa, namhyung, sdf

Em Tue, Mar 12, 2019 at 02:10:23PM +0100, Jiri Olsa escreveu:
> On Mon, Mar 11, 2019 at 10:30:43PM -0700, Song Liu wrote:
> 
> SNIP
> 
> > +static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
> > +{
> > +	struct perf_env *env = &ff->ph->env;
> > +	struct rb_root *root;
> > +	struct rb_node *next;
> > +
> > +	down_read(&env->bpf_progs.lock);
> > +
> > +	root = &env->bpf_progs.infos;
> > +	next = rb_first(root);
> > +
> > +	while (next) {
> > +		struct bpf_prog_info_node *node;
> > +
> > +		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
> > +		next = rb_next(&node->rb_node);
> > +		fprintf(fp, "# bpf_prog_info of id %u\n",
> > +			node->info_linear->info.id);
> 
> so report displays bpf prog dso/name like:
> 
>    0.02%  ls           bpf_prog_c80ffe554aba1bec_syscall_enter_o  [k] bpf_prog_c80ffe554aba1bec_syscall_enter_o                                                                                       ▒
> 
> and 'perf report --header-only -I' shows:
> 
> 
> 	# bpf_prog_info of id 17
> 	# bpf_prog_info of id 18
> 	# bpf_prog_info of id 19
> 	# bpf_prog_info of id 20
> 	# bpf_prog_info of id 21
> 	# bpf_prog_info of id 22
> 	# bpf_prog_info of id 25
> 	# bpf_prog_info of id 26
> 	# bpf_prog_info of id 34
> 	# bpf_prog_info of id 35
> 
> could we have something more detailed like bpftool output:
> 
> 	34: tracepoint  name syscall_enter_o  tag c80ffe554aba1bec  gpl
> 		loaded_at 2019-03-12T14:02:03+0100  uid 0
> 		xlated 360B  jited 232B  memlock 4096B  map_ids 30
> 
> 	35: tracepoint  name syscall_enter_o  tag ada5ccbe5576399c  gpl
> 		loaded_at 2019-03-12T14:02:03+0100  uid 0
> 		xlated 352B  jited 228B  memlock 4096B  map_ids 30
> 
> 
> could be on top of this patchset

Yeah, please, and can we have the name of programs that loaded that
program there as well? 8-)

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
@ 2019-03-12 15:00   ` Arnaldo Carvalho de Melo
  2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 15:00 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:44PM -0700, Song Liu escreveu:
>  static void perf_env__purge_bpf(struct perf_env *env)
>  {
> @@ -83,6 +135,19 @@ static void perf_env__purge_bpf(struct perf_env *env)
>  		rb_erase(&node->rb_node, root);
>  		free(node);
>  	}
> +
> +	root = &env->bpf_progs.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(&node->rb_node, root);
> +		free(node);
> +	}

Added this as well:

	env->bpf_progs.btfs_cnt = 0;

> +
>  	up_write(&env->bpf_progs.lock);
>  }

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
@ 2019-03-12 15:14   ` Arnaldo Carvalho de Melo
  2019-03-12 15:16     ` Arnaldo Carvalho de Melo
  2019-03-22 22:40   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
  1 sibling, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 15:14 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
> This patch enables perf-record to save btf information as headers to
> perf.data A new header type HEADER_BPF_BTF is introduced for this data.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/perf/util/header.c | 101 ++++++++++++++++++++++++++++++++++++++-
>  tools/perf/util/header.h |   1 +
>  2 files changed, 101 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index a4ef8f657ad0..7decd2d1dbda 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -905,6 +905,39 @@ static int write_bpf_prog_info(struct feat_fd *ff,
>  	return ret;
>  }
>  
> +static int write_bpf_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;
> +	int ret;
> +
> +	down_read(&env->bpf_progs.lock);
> +
> +	ret = do_write(ff, &env->bpf_progs.btfs_cnt,
> +		       sizeof(env->bpf_progs.btfs_cnt));
> +
> +	if (ret < 0)
> +		goto out;
> +
> +	root = &env->bpf_progs.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);
> +		ret = do_write(ff, &node->id,
> +			       sizeof(u32) * 2 + node->data_size);
> +		if (ret < 0)
> +			goto out;
> +	}
> +out:
> +	up_read(&env->bpf_progs.lock);
> +	return ret;
> +}
> +
>  static int cpu_cache_level__sort(const void *a, const void *b)
>  {
>  	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
> @@ -1408,6 +1441,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
>  	up_read(&env->bpf_progs.lock);
>  }
>  
> +static void print_bpf_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_progs.lock);
> +
> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);

So, I couldn't get this to work right now, and I have BPF programs that
are loaded and that have BTF info:

[root@quaco ~]# bpftool prog | tail -6
208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
	loaded_at 2019-03-12T11:16:55-0300  uid 0
	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
	loaded_at 2019-03-12T11:16:55-0300  uid 0
	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
[root@quaco ~]#


[root@quaco ~]# bpftool map  | tail -6
105: perf_event_array  name __augmented_sys  flags 0x0
	key 4B  value 4B  max_entries 8  memlock 4096B
106: array  name syscalls  flags 0x0
	key 4B  value 1B  max_entries 512  memlock 8192B
107: hash  name pids_filtered  flags 0x0
	key 4B  value 1B  max_entries 64  memlock 8192B
[root@quaco ~]#

[root@quaco ~]# bpftool map dump id 107
[{
        "key": 8104,
        "value": true
    },{
        "key": 18868,
        "value": true
    }
]
[root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
 8104 pts/8    S+     0:07 trace -e recvmmsg
18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
[root@quaco ~]#

So I was expecting to see those btf lines there :-\

All the patches up to this point I have already merged and tested in my
local branch.

Will continue right after lunch to try to figure out why this BTF info
isn't landing on this new header feature...

- Arnaldo



> +	}
> +
> +	up_read(&env->bpf_progs.lock);
> +}
> +
>  static void free_event_desc(struct perf_evsel *events)
>  {
>  	struct perf_evsel *evsel;
> @@ -2509,6 +2564,49 @@ static int process_bpf_prog_info(struct feat_fd *ff,
>  	return err;
>  }
>  
> +static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
> +{
> +	struct perf_env *env = &ff->ph->env;
> +	u32 count, i;
> +
> +	if (ff->ph->needs_swap) {
> +		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
> +		return 0;
> +	}
> +
> +	if (do_read_u32(ff, &count))
> +		return -1;
> +
> +	down_write(&env->bpf_progs.lock);
> +
> +	for (i = 0; i < count; ++i) {
> +		struct btf_node *node;
> +		u32 id, data_size;
> +
> +		if (do_read_u32(ff, &id))
> +			return -1;
> +		if (do_read_u32(ff, &data_size))
> +			return -1;
> +
> +		node = malloc(sizeof(struct btf_node) + data_size);
> +		if (!node)
> +			return -1;
> +
> +		node->id = id;
> +		node->data_size = data_size;
> +
> +		if (__do_read(ff, node->data, data_size)) {
> +			free(node);
> +			return -1;
> +		}
> +
> +		perf_env__insert_btf(env, node);
> +	}
> +
> +	up_write(&env->bpf_progs.lock);
> +	return 0;
> +}
> +
>  struct feature_ops {
>  	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
>  	void (*print)(struct feat_fd *ff, FILE *fp);
> @@ -2569,7 +2667,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(BPF_BTF,       bpf_btf,        false)
>  };
>  
>  struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index 0785c91b4c3a..9e7d931f7c0d 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_BPF_BTF,
>  	HEADER_LAST_FEATURE,
>  	HEADER_FEAT_BITS	= 256,
>  };
> -- 
> 2.17.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12 15:14   ` Arnaldo Carvalho de Melo
@ 2019-03-12 15:16     ` Arnaldo Carvalho de Melo
  2019-03-12 16:26       ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 15:16 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Tue, Mar 12, 2019 at 12:14:05PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
> > +static void print_bpf_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_progs.lock);
> > +
> > +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
> 
> So, I couldn't get this to work right now, and I have BPF programs that
> are loaded and that have BTF info:
> 
> [root@quaco ~]# bpftool prog | tail -6
> 208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> 	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
> 209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> 	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
> [root@quaco ~]#
> 
> 
> [root@quaco ~]# bpftool map  | tail -6
> 105: perf_event_array  name __augmented_sys  flags 0x0
> 	key 4B  value 4B  max_entries 8  memlock 4096B
> 106: array  name syscalls  flags 0x0
> 	key 4B  value 1B  max_entries 512  memlock 8192B
> 107: hash  name pids_filtered  flags 0x0
> 	key 4B  value 1B  max_entries 64  memlock 8192B
> [root@quaco ~]#
> 
> [root@quaco ~]# bpftool map dump id 107
> [{
>         "key": 8104,
>         "value": true
>     },{
>         "key": 18868,
>         "value": true
>     }
> ]
> [root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
>  8104 pts/8    S+     0:07 trace -e recvmmsg
> 18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
> [root@quaco ~]#
> 
> So I was expecting to see those btf lines there :-\
> 
> All the patches up to this point I have already merged and tested in my
> local branch.
> 
> Will continue right after lunch to try to figure out why this BTF info
> isn't landing on this new header feature...

I've pushed what I have to my git.kernel.org repo, branch
tmp.perf/bpf-annotate.

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tmp.perf/bpf-annotate

The HEAD is this cset.

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12 15:16     ` Arnaldo Carvalho de Melo
@ 2019-03-12 16:26       ` Song Liu
  2019-03-12 17:05         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12 16:26 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf



> On Mar 12, 2019, at 8:16 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Tue, Mar 12, 2019 at 12:14:05PM -0300, Arnaldo Carvalho de Melo escreveu:
>> Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
>>> +static void print_bpf_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_progs.lock);
>>> +
>>> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
>> 
>> So, I couldn't get this to work right now, and I have BPF programs that
>> are loaded and that have BTF info:
>> 
>> [root@quaco ~]# bpftool prog | tail -6
>> 208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
>> 	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
>> 209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
>> 	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
>> [root@quaco ~]#
>> 
>> 
>> [root@quaco ~]# bpftool map  | tail -6
>> 105: perf_event_array  name __augmented_sys  flags 0x0
>> 	key 4B  value 4B  max_entries 8  memlock 4096B
>> 106: array  name syscalls  flags 0x0
>> 	key 4B  value 1B  max_entries 512  memlock 8192B
>> 107: hash  name pids_filtered  flags 0x0
>> 	key 4B  value 1B  max_entries 64  memlock 8192B
>> [root@quaco ~]#
>> 
>> [root@quaco ~]# bpftool map dump id 107
>> [{
>>        "key": 8104,
>>        "value": true
>>    },{
>>        "key": 18868,
>>        "value": true
>>    }
>> ]
>> [root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
>> 8104 pts/8    S+     0:07 trace -e recvmmsg
>> 18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
>> [root@quaco ~]#
>> 
>> So I was expecting to see those btf lines there :-\
>> 
>> All the patches up to this point I have already merged and tested in my
>> local branch.
>> 
>> Will continue right after lunch to try to figure out why this BTF info
>> isn't landing on this new header feature...
> 
> I've pushed what I have to my git.kernel.org repo, branch
> tmp.perf/bpf-annotate.
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tmp.perf/bpf-annotate
> 
> The HEAD is this cset.
> 
> - Arnaldo

I am not sure I fully understand the problem here. 

I can get BTF information from this version:

# ~/perf report --header-only  | grep btf
# btf info of id 504

Thanks,
Song


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12 16:26       ` Song Liu
@ 2019-03-12 17:05         ` Arnaldo Carvalho de Melo
  2019-03-12 17:29           ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-12 17:05 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf

Em Tue, Mar 12, 2019 at 04:26:17PM +0000, Song Liu escreveu:
> 
> 
> > On Mar 12, 2019, at 8:16 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > 
> > Em Tue, Mar 12, 2019 at 12:14:05PM -0300, Arnaldo Carvalho de Melo escreveu:
> >> Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
> >>> +static void print_bpf_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_progs.lock);
> >>> +
> >>> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
> >> 
> >> So, I couldn't get this to work right now, and I have BPF programs that
> >> are loaded and that have BTF info:
> >> 
> >> [root@quaco ~]# bpftool prog | tail -6
> >> 208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
> >> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> >> 	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
> >> 209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
> >> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> >> 	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
> >> [root@quaco ~]#
> >> 
> >> 
> >> [root@quaco ~]# bpftool map  | tail -6
> >> 105: perf_event_array  name __augmented_sys  flags 0x0
> >> 	key 4B  value 4B  max_entries 8  memlock 4096B
> >> 106: array  name syscalls  flags 0x0
> >> 	key 4B  value 1B  max_entries 512  memlock 8192B
> >> 107: hash  name pids_filtered  flags 0x0
> >> 	key 4B  value 1B  max_entries 64  memlock 8192B
> >> [root@quaco ~]#
> >> 
> >> [root@quaco ~]# bpftool map dump id 107
> >> [{
> >>        "key": 8104,
> >>        "value": true
> >>    },{
> >>        "key": 18868,
> >>        "value": true
> >>    }
> >> ]
> >> [root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
> >> 8104 pts/8    S+     0:07 trace -e recvmmsg
> >> 18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
> >> [root@quaco ~]#
> >> 
> >> So I was expecting to see those btf lines there :-\
> >> 
> >> All the patches up to this point I have already merged and tested in my
> >> local branch.
> >> 
> >> Will continue right after lunch to try to figure out why this BTF info
> >> isn't landing on this new header feature...
> > 
> > I've pushed what I have to my git.kernel.org repo, branch
> > tmp.perf/bpf-annotate.
> > 
> > git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tmp.perf/bpf-annotate
> > 
> > The HEAD is this cset.

> I am not sure I fully understand the problem here. 

Trying to say it another way, when I start 'perf record', with the
patches in your series up to this one ('[PATCH v9 perf,bpf 09/15] perf,
bpf: save btf information as headers to perf.data'), and while there is
a BPF program running, that has BTF attached to it as can be seen by
using 'bpf map dump', 'perf report --header-only' isn't showing any line
with 'btf' on it.

So, using -v I notice that it is failing to get enable attr.bpf_event
and attr.ksymbol, which makes me go get another coffee to check that the
kernel was built from my 5.1 tree that has those events and not 5.0 that
doesn't ;-\ Sorry for the noise, will get back here after I check all
this :-)

But to recap, the BPF events I was getting were the synthesized ones...

[root@quaco ~]# perf record -vv
Using CPUID GenuineIntel-6-8E-A
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
nr_cblocks: 0
affinity: SYS
------------------------------------------------------------
perf_event_attr:
  size                             112
  { sample_period, sample_freq }   4000
  sample_type                      IP|TID|TIME|CPU|PERIOD
  read_format                      ID
  disabled                         1
  inherit                          1
  mmap                             1
  comm                             1
  freq                             1
  task                             1
  precise_ip                       3
  sample_id_all                    1
  exclude_guest                    1
  mmap2                            1
  comm_exec                        1
  ksymbol                          1
  bpf_event                        1
------------------------------------------------------------
sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open failed, error -22
switching off bpf_event
------------------------------------------------------------
perf_event_attr:
  size                             112
  { sample_period, sample_freq }   4000
  sample_type                      IP|TID|TIME|CPU|PERIOD
  read_format                      ID
  disabled                         1
  inherit                          1
  mmap                             1
  comm                             1
  freq                             1
  task                             1
  precise_ip                       3
  sample_id_all                    1
  exclude_guest                    1
  mmap2                            1
  comm_exec                        1
  ksymbol                          1
------------------------------------------------------------
sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
sys_perf_event_open failed, error -22
switching off ksymbol
------------------------------------------------------------
perf_event_attr:
  size                             112
  { sample_period, sample_freq }   4000
  sample_type                      IP|TID|TIME|CPU|PERIOD
  read_format                      ID
  disabled                         1
  inherit                          1
  mmap                             1
  comm                             1
  freq                             1
  task                             1
  precise_ip                       3
  sample_id_all                    1
  exclude_guest                    1
  mmap2                            1
  comm_exec                        1
------------------------------------------------------------
sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8 = 4
sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8 = 5
sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8 = 6
sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8 = 7
sys_perf_event_open: pid -1  cpu 4  group_fd -1  flags 0x8 = 8
sys_perf_event_open: pid -1  cpu 5  group_fd -1  flags 0x8 = 9
sys_perf_event_open: pid -1  cpu 6  group_fd -1  flags 0x8 = 10
sys_perf_event_open: pid -1  cpu 7  group_fd -1  flags 0x8 = 11
mmap size 528384B
perf event ring buffer mmapped per cpu
Synthesizing TSC conversion information



^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12 17:05         ` Arnaldo Carvalho de Melo
@ 2019-03-12 17:29           ` Song Liu
  2019-03-15 19:06             ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-12 17:29 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf



> On Mar 12, 2019, at 10:05 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Tue, Mar 12, 2019 at 04:26:17PM +0000, Song Liu escreveu:
>> 
>> 
>>> On Mar 12, 2019, at 8:16 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
>>> 
>>> Em Tue, Mar 12, 2019 at 12:14:05PM -0300, Arnaldo Carvalho de Melo escreveu:
>>>> Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
>>>>> +static void print_bpf_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_progs.lock);
>>>>> +
>>>>> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
>>>> 
>>>> So, I couldn't get this to work right now, and I have BPF programs that
>>>> are loaded and that have BTF info:
>>>> 
>>>> [root@quaco ~]# bpftool prog | tail -6
>>>> 208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
>>>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
>>>> 	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
>>>> 209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
>>>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
>>>> 	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
>>>> [root@quaco ~]#
>>>> 
>>>> 
>>>> [root@quaco ~]# bpftool map  | tail -6
>>>> 105: perf_event_array  name __augmented_sys  flags 0x0
>>>> 	key 4B  value 4B  max_entries 8  memlock 4096B
>>>> 106: array  name syscalls  flags 0x0
>>>> 	key 4B  value 1B  max_entries 512  memlock 8192B
>>>> 107: hash  name pids_filtered  flags 0x0
>>>> 	key 4B  value 1B  max_entries 64  memlock 8192B
>>>> [root@quaco ~]#
>>>> 
>>>> [root@quaco ~]# bpftool map dump id 107
>>>> [{
>>>>       "key": 8104,
>>>>       "value": true
>>>>   },{
>>>>       "key": 18868,
>>>>       "value": true
>>>>   }
>>>> ]
>>>> [root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
>>>> 8104 pts/8    S+     0:07 trace -e recvmmsg
>>>> 18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
>>>> [root@quaco ~]#
>>>> 
>>>> So I was expecting to see those btf lines there :-\
>>>> 
>>>> All the patches up to this point I have already merged and tested in my
>>>> local branch.
>>>> 
>>>> Will continue right after lunch to try to figure out why this BTF info
>>>> isn't landing on this new header feature...
>>> 
>>> I've pushed what I have to my git.kernel.org repo, branch
>>> tmp.perf/bpf-annotate.
>>> 
>>> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tmp.perf/bpf-annotate
>>> 
>>> The HEAD is this cset.
> 
>> I am not sure I fully understand the problem here. 
> 
> Trying to say it another way, when I start 'perf record', with the
> patches in your series up to this one ('[PATCH v9 perf,bpf 09/15] perf,
> bpf: save btf information as headers to perf.data'), and while there is
> a BPF program running, that has BTF attached to it as can be seen by
> using 'bpf map dump', 'perf report --header-only' isn't showing any line
> with 'btf' on it.
> 
> So, using -v I notice that it is failing to get enable attr.bpf_event
> and attr.ksymbol, which makes me go get another coffee to check that the
> kernel was built from my 5.1 tree that has those events and not 5.0 that
> doesn't ;-\ Sorry for the noise, will get back here after I check all
> this :-)
> 
> But to recap, the BPF events I was getting were the synthesized ones...

Yeah, to capture the short living BPF/BTF, we need patch 15/15 of the set. 

Thanks,
Song

> 
> [root@quaco ~]# perf record -vv
> Using CPUID GenuineIntel-6-8E-A
> intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
> nr_cblocks: 0
> affinity: SYS
> ------------------------------------------------------------
> perf_event_attr:
>  size                             112
>  { sample_period, sample_freq }   4000
>  sample_type                      IP|TID|TIME|CPU|PERIOD
>  read_format                      ID
>  disabled                         1
>  inherit                          1
>  mmap                             1
>  comm                             1
>  freq                             1
>  task                             1
>  precise_ip                       3
>  sample_id_all                    1
>  exclude_guest                    1
>  mmap2                            1
>  comm_exec                        1
>  ksymbol                          1
>  bpf_event                        1
> ------------------------------------------------------------
> sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
> sys_perf_event_open failed, error -22
> switching off bpf_event
> ------------------------------------------------------------
> perf_event_attr:
>  size                             112
>  { sample_period, sample_freq }   4000
>  sample_type                      IP|TID|TIME|CPU|PERIOD
>  read_format                      ID
>  disabled                         1
>  inherit                          1
>  mmap                             1
>  comm                             1
>  freq                             1
>  task                             1
>  precise_ip                       3
>  sample_id_all                    1
>  exclude_guest                    1
>  mmap2                            1
>  comm_exec                        1
>  ksymbol                          1
> ------------------------------------------------------------
> sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
> sys_perf_event_open failed, error -22
> switching off ksymbol
> ------------------------------------------------------------
> perf_event_attr:
>  size                             112
>  { sample_period, sample_freq }   4000
>  sample_type                      IP|TID|TIME|CPU|PERIOD
>  read_format                      ID
>  disabled                         1
>  inherit                          1
>  mmap                             1
>  comm                             1
>  freq                             1
>  task                             1
>  precise_ip                       3
>  sample_id_all                    1
>  exclude_guest                    1
>  mmap2                            1
>  comm_exec                        1
> ------------------------------------------------------------
> sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8 = 4
> sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8 = 5
> sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8 = 6
> sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8 = 7
> sys_perf_event_open: pid -1  cpu 4  group_fd -1  flags 0x8 = 8
> sys_perf_event_open: pid -1  cpu 5  group_fd -1  flags 0x8 = 9
> sys_perf_event_open: pid -1  cpu 6  group_fd -1  flags 0x8 = 10
> sys_perf_event_open: pid -1  cpu 7  group_fd -1  flags 0x8 = 11
> mmap size 528384B
> perf event ring buffer mmapped per cpu
> Synthesizing TSC conversion information


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
  2019-03-12 13:10   ` Jiri Olsa
@ 2019-03-13 19:05   ` Arnaldo Carvalho de Melo
  2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
  2 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-13 19:05 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:43PM -0700, Song Liu escreveu:
> +static int write_bpf_prog_info(struct feat_fd *ff,
> +			       struct perf_evlist *evlist __maybe_unused)
> +{
> +	struct perf_env *env = &ff->ph->env;
> +	struct rb_root *root;
> +	struct rb_node *next;
> +	int ret;
> +
> +	down_read(&env->bpf_progs.lock);
> +
> +	ret = do_write(ff, &env->bpf_progs.infos_cnt,
> +		       sizeof(env->bpf_progs.infos_cnt));
> +	if (ret < 0)
> +		goto out;
> +
> +	root = &env->bpf_progs.infos;
> +	next = rb_first(root);
> +	while (next) {
> +		struct bpf_prog_info_node *node;
> +		size_t len;
> +
> +		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
> +		next = rb_next(&node->rb_node);
> +		len = sizeof(struct bpf_prog_info_linear) +
> +			node->info_linear->data_len;
> +
> +		/* before writing to file, translate address to offset */
> +		bpf_program__bpil_addr_to_offs(node->info_linear);
> +		ret = do_write(ff, node->info_linear, len);
> +		/*
> +		 * translate back to address even when do_write() fails,
> +		 * so that this function never changes the data.
> +		 */
> +		bpf_program__bpil_offs_to_addr(node->info_linear);
> +		if (ret < 0)
> +			goto out;
> +	}
> +out:
> +	up_read(&env->bpf_progs.lock);
> +	return ret;
> +}

The above uses libbpf functions unconditionally, leading to build
failures when NO_LIBBPF=1 is passed or libbpf somehow is not available
or can't be built.

So I added this:

+#else // HAVE_LIBBPF_SUPPORT
+static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
+                              struct perf_evlist *evlist __maybe_unused)
+{
+       return 0;
+}
+#endif // HAVE_LIBBPF_SUPPORT

And added this committer notes:

    Committer notes:
    
    We can't use the libbpf unconditionally, as the build may have been with
    NO_LIBBPF, when we end up with linking errors, so provide a dummy
    write_bpf_prog_info() wrapped by HAVE_LIBBPF_SUPPORT for that case.
    
    Reading and printing are not affected by this, so can continue as is.


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
@ 2019-03-13 21:00   ` Arnaldo Carvalho de Melo
  2019-03-13 21:08     ` Arnaldo Carvalho de Melo
  2019-03-22 22:37   ` [tip:perf/urgent] perf bpf: Synthesize " tip-bot for Song Liu
  1 sibling, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-13 21:00 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:40PM -0700, Song Liu escreveu:
> 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 ea012b735a37..e9d9854be506 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);

Need this:

-               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
+               u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);


To overcome this on debian:experimental-x-mips, i.e. Debian Experimental
cross building to MIPS 32-bit:

util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
                                   ^
util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
                      ^
util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
                       ^
util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   void *func_infos = (void *)(info->func_info);
                      ^
  CC       /tmp/build/perf/util/pmu.o
  CC       /tmp/build/perf/util/pmu-flex.o
cc1: all warnings being treated as errors


> +		__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

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-13 21:00   ` Arnaldo Carvalho de Melo
@ 2019-03-13 21:08     ` Arnaldo Carvalho de Melo
  2019-03-14  5:08       ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-13 21:08 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Wed, Mar 13, 2019 at 06:00:30PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Mar 11, 2019 at 10:30:40PM -0700, Song Liu escreveu:
> > -
> >  	/* Synthesize PERF_RECORD_KSYMBOL */
> >  	for (i = 0; i < sub_prog_cnt; i++) {
> > +		u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
> 
> Need this:
> 
> -               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
> +               u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
> 
> 
> To overcome this on debian:experimental-x-mips, i.e. Debian Experimental
> cross building to MIPS 32-bit:
> 
> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>    u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>                                    ^
> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>    __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
>                       ^
> util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>    __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
>                        ^
> util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>    void *func_infos = (void *)(info->func_info);
>                       ^
>   CC       /tmp/build/perf/util/pmu.o
>   CC       /tmp/build/perf/util/pmu-flex.o
> cc1: all warnings being treated as errors

Argh, hit the send button too fast, that is not the only case and then
my change just changed the error:

util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
                                   ^
util/bpf-event.c:143:35: error: initialization of 'u8 (*)[8]' {aka 'unsigned char (*)[8]'} from incompatible pointer type 'u8 *' {aka 'unsigned char *'} [-Werror=incompatible-pointer-types]
util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
                      ^
util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
                       ^
util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
   void *func_infos = (void *)(info->func_info);
                      ^
  CC       /tmp/build/perf/util/pmu.o
  CC       /tmp/build/perf/util/pmu-flex.o
cc1: all warnings being treated as errors
mv: cannot stat '/tmp/build/perf/util/.bpf-event.o.tmp': No such file or directory


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-13 21:08     ` Arnaldo Carvalho de Melo
@ 2019-03-14  5:08       ` Song Liu
  2019-03-14 16:45         ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-14  5:08 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, jolsa, namhyung, sdf



> On Mar 13, 2019, at 2:08 PM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Wed, Mar 13, 2019 at 06:00:30PM -0300, Arnaldo Carvalho de Melo escreveu:
>> Em Mon, Mar 11, 2019 at 10:30:40PM -0700, Song Liu escreveu:
>>> -
>>> 	/* Synthesize PERF_RECORD_KSYMBOL */
>>> 	for (i = 0; i < sub_prog_cnt; i++) {
>>> +		u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>> 
>> Need this:
>> 
>> -               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>> +               u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
>> 
>> 
>> To overcome this on debian:experimental-x-mips, i.e. Debian Experimental
>> cross building to MIPS 32-bit:
>> 
>> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
>> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>   u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>>                                   ^
>> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>   __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
>>                      ^
>> util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>   __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
>>                       ^
>> util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>   void *func_infos = (void *)(info->func_info);
>>                      ^
>>  CC       /tmp/build/perf/util/pmu.o
>>  CC       /tmp/build/perf/util/pmu-flex.o
>> cc1: all warnings being treated as errors
> 
> Argh, hit the send button too fast, that is not the only case and then
> my change just changed the error:
> 
> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
>                                   ^
> util/bpf-event.c:143:35: error: initialization of 'u8 (*)[8]' {aka 'unsigned char (*)[8]'} from incompatible pointer type 'u8 *' {aka 'unsigned char *'} [-Werror=incompatible-pointer-types]
> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
>                      ^
> util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
>                       ^
> util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>   void *func_infos = (void *)(info->func_info);
>                      ^
>  CC       /tmp/build/perf/util/pmu.o
>  CC       /tmp/build/perf/util/pmu-flex.o
> cc1: all warnings being treated as errors
> mv: cannot stat '/tmp/build/perf/util/.bpf-event.o.tmp': No such file or directory
> 

We can fix it with the following:

-               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);
+               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(intptr_t)(info->prog_tags);
+               __u32 *prog_lens = (__u32 *)(intptr_t)(info->jited_func_lens);
+               __u64 *prog_addrs = (__u64 *)(intptr_t)(info->jited_ksyms);
+               void *func_infos = (void *)(intptr_t)(info->func_info);

Thanks,
Song


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-14  5:08       ` Song Liu
@ 2019-03-14 16:45         ` Song Liu
  2019-03-14 18:30           ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-14 16:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, jolsa, namhyung, sdf



> On Mar 13, 2019, at 10:08 PM, Song Liu <songliubraving@fb.com> wrote:
> 
> 
> 
>> On Mar 13, 2019, at 2:08 PM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
>> 
>> Em Wed, Mar 13, 2019 at 06:00:30PM -0300, Arnaldo Carvalho de Melo escreveu:
>>> Em Mon, Mar 11, 2019 at 10:30:40PM -0700, Song Liu escreveu:
>>>> -
>>>> 	/* Synthesize PERF_RECORD_KSYMBOL */
>>>> 	for (i = 0; i < sub_prog_cnt; i++) {
>>>> +		u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>>> 
>>> Need this:
>>> 
>>> -               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>>> +               u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
>>> 
>>> 
>>> To overcome this on debian:experimental-x-mips, i.e. Debian Experimental
>>> cross building to MIPS 32-bit:
>>> 
>>> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
>>> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>>  u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
>>>                                  ^
>>> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>>  __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
>>>                     ^
>>> util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>>  __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
>>>                      ^
>>> util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>>  void *func_infos = (void *)(info->func_info);
>>>                     ^
>>> CC       /tmp/build/perf/util/pmu.o
>>> CC       /tmp/build/perf/util/pmu-flex.o
>>> cc1: all warnings being treated as errors
>> 
>> Argh, hit the send button too fast, that is not the only case and then
>> my change just changed the error:
>> 
>> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
>> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>  u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
>>                                  ^
>> util/bpf-event.c:143:35: error: initialization of 'u8 (*)[8]' {aka 'unsigned char (*)[8]'} from incompatible pointer type 'u8 *' {aka 'unsigned char *'} [-Werror=incompatible-pointer-types]
>> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>  __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
>>                     ^
>> util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>  __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
>>                      ^
>> util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
>>  void *func_infos = (void *)(info->func_info);
>>                     ^
>> CC       /tmp/build/perf/util/pmu.o
>> CC       /tmp/build/perf/util/pmu-flex.o
>> cc1: all warnings being treated as errors
>> mv: cannot stat '/tmp/build/perf/util/.bpf-event.o.tmp': No such file or directory
>> 
> 
> We can fix it with the following:
> 
> -               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);
> +               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(intptr_t)(info->prog_tags);
> +               __u32 *prog_lens = (__u32 *)(intptr_t)(info->jited_func_lens);
> +               __u64 *prog_addrs = (__u64 *)(intptr_t)(info->jited_ksyms);
> +               void *func_infos = (void *)(intptr_t)(info->func_info);
> 
> Thanks,
> Song

Actually, I think uintptr_t is better than intptr_t here. 

Thanks,
Song

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-14 16:45         ` Song Liu
@ 2019-03-14 18:30           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-14 18:30 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, jolsa, namhyung, sdf

Em Thu, Mar 14, 2019 at 04:45:22PM +0000, Song Liu escreveu:
> > On Mar 13, 2019, at 10:08 PM, Song Liu <songliubraving@fb.com> wrote:
> >> On Mar 13, 2019, at 2:08 PM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> >> Em Wed, Mar 13, 2019 at 06:00:30PM -0300, Arnaldo Carvalho de Melo escreveu:
> >>> Em Mon, Mar 11, 2019 at 10:30:40PM -0700, Song Liu escreveu:
> >>>> 	/* Synthesize PERF_RECORD_KSYMBOL */
> >>>> 	for (i = 0; i < sub_prog_cnt; i++) {
> >>>> +		u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
> >>> Need this:
> >>> -               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
> >>> +               u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);
> >>> 
> >>> To overcome this on debian:experimental-x-mips, i.e. Debian Experimental
> >>> cross building to MIPS 32-bit:

> >>> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
> >>> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> >>>  u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);

> >> Argh, hit the send button too fast, that is not the only case and then
> >> my change just changed the error:

> >> util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
> >> util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> >>  u8 (*prog_tags)[BPF_TAG_SIZE] = (u8 *)(info->prog_tags);

> >> util/bpf-event.c:143:35: error: initialization of 'u8 (*)[8]' {aka 'unsigned char (*)[8]'} from incompatible pointer type 'u8 *' {aka 'unsigned char *'} [-Werror=incompatible-pointer-types]
> >> util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> >>  __u32 *prog_lens = (__u32 *)(info->jited_func_lens);


> >> cc1: all warnings being treated as errors
> >> mv: cannot stat '/tmp/build/perf/util/.bpf-event.o.tmp': No such file or directory

> > We can fix it with the following:

> > -               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);
> > +               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(intptr_t)(info->prog_tags);
> > +               __u32 *prog_lens = (__u32 *)(intptr_t)(info->jited_func_lens);
> > +               __u64 *prog_addrs = (__u64 *)(intptr_t)(info->jited_ksyms);
> > +               void *func_infos = (void *)(intptr_t)(info->func_info);
 
> Actually, I think uintptr_t is better than intptr_t here. 

Yeap, did the trick:

$ dm debian:experimental-x-mips
   1   debian:experimental-x-mips    : Ok   mips-linux-gnu-gcc (Debian 8.3.0-2) 8.3.0
$

Works as well with x86_64 with a recent distro such as fedora:30 or
ubuntu:19.04, building it with both gcc and clang:

$ dm fedora:30 ubuntu:19.04
   1 fedora:30    : Ok   gcc (GCC) 9.0.1 20190227 (Red Hat 9.0.1-0.8), clang version 8.0.0 (Fedora 8.0.0-0.5.rc3.fc30)
   2 ubuntu:19.04 : Ok   gcc (Ubuntu 8.3.0-2ubuntu2) 8.3.0, clang version 8.0.0-+rc4-1ubuntu1 (tags/RELEASE_800/rc4)
$

Continuing with the review/tests...

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-12 17:29           ` Song Liu
@ 2019-03-15 19:06             ` Arnaldo Carvalho de Melo
  2019-03-15 19:26               ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-15 19:06 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf

Em Tue, Mar 12, 2019 at 05:29:03PM +0000, Song Liu escreveu:
> > On Mar 12, 2019, at 10:05 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > Em Tue, Mar 12, 2019 at 04:26:17PM +0000, Song Liu escreveu:
> >>> On Mar 12, 2019, at 8:16 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> >>> Em Tue, Mar 12, 2019 at 12:14:05PM -0300, Arnaldo Carvalho de Melo escreveu:
> >>>> Em Mon, Mar 11, 2019 at 10:30:45PM -0700, Song Liu escreveu:
> >>>>> +static void print_bpf_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_progs.lock);
> >>>>> +
> >>>>> +	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
> >>>> 
> >>>> So, I couldn't get this to work right now, and I have BPF programs that
> >>>> are loaded and that have BTF info:
> >>>> 
> >>>> [root@quaco ~]# bpftool prog | tail -6
> >>>> 208: tracepoint  name sys_enter  tag 819967866022f1e1  gpl
> >>>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> >>>> 	xlated 528B  jited 381B  memlock 4096B  map_ids 107,106,105
> >>>> 209: tracepoint  name sys_exit  tag c1bd85c092d6e4aa  gpl
> >>>> 	loaded_at 2019-03-12T11:16:55-0300  uid 0
> >>>> 	xlated 256B  jited 191B  memlock 4096B  map_ids 107,106
> >>>> [root@quaco ~]#
> >>>> 
> >>>> 
> >>>> [root@quaco ~]# bpftool map  | tail -6
> >>>> 105: perf_event_array  name __augmented_sys  flags 0x0
> >>>> 	key 4B  value 4B  max_entries 8  memlock 4096B
> >>>> 106: array  name syscalls  flags 0x0
> >>>> 	key 4B  value 1B  max_entries 512  memlock 8192B
> >>>> 107: hash  name pids_filtered  flags 0x0
> >>>> 	key 4B  value 1B  max_entries 64  memlock 8192B
> >>>> [root@quaco ~]#
> >>>> 
> >>>> [root@quaco ~]# bpftool map dump id 107
> >>>> [{
> >>>>       "key": 8104,
> >>>>       "value": true
> >>>>   },{
> >>>>       "key": 18868,
> >>>>       "value": true
> >>>>   }
> >>>> ]
> >>>> [root@quaco ~]# ps ax|egrep 8104\|18868 | grep -v grep
> >>>> 8104 pts/8    S+     0:07 trace -e recvmmsg
> >>>> 18868 ?        Ssl   21:21 /usr/libexec/gnome-terminal-server
> >>>> [root@quaco ~]#
> >>>> 
> >>>> So I was expecting to see those btf lines there :-\
> >>>> 
> >>>> All the patches up to this point I have already merged and tested in my
> >>>> local branch.
> >>>> 
> >>>> Will continue right after lunch to try to figure out why this BTF info
> >>>> isn't landing on this new header feature...
> >>> 
> >>> I've pushed what I have to my git.kernel.org repo, branch
> >>> tmp.perf/bpf-annotate.
> >>> 
> >>> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tmp.perf/bpf-annotate
> >>> 
> >>> The HEAD is this cset.
> > 
> >> I am not sure I fully understand the problem here. 
> > 
> > Trying to say it another way, when I start 'perf record', with the
> > patches in your series up to this one ('[PATCH v9 perf,bpf 09/15] perf,
> > bpf: save btf information as headers to perf.data'), and while there is
> > a BPF program running, that has BTF attached to it as can be seen by
> > using 'bpf map dump', 'perf report --header-only' isn't showing any line
> > with 'btf' on it.
> > 
> > So, using -v I notice that it is failing to get enable attr.bpf_event
> > and attr.ksymbol, which makes me go get another coffee to check that the
> > kernel was built from my 5.1 tree that has those events and not 5.0 that
> > doesn't ;-\ Sorry for the noise, will get back here after I check all
> > this :-)
> > 
> > But to recap, the BPF events I was getting were the synthesized ones...
> 
> Yeah, to capture the short living BPF/BTF, we need patch 15/15 of the set. 

So, I continue trying to test this with the patches applied up to the
patch in the subject of this message, i.e. up to:

  09/15 perf, bpf: save btf information as headers to perf.data

While running on a kernel based on tip/perf/core, so it should have what
is needed:

  [root@quaco ~]# egrep 't perf_event_(bpf|ksymbol)_output' /proc/kallsyms
  ffffffff94211a40 t perf_event_bpf_output
  ffffffff94216550 t perf_event_ksymbol_output
  [root@quaco ~]#

But when I debug breakpointing perf_event__synthesize_one_bpf_prog(),
bpf_prog_info->btf_info is always zero, i.e. here:

        /* check BTF func info support */
        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) {
                        pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__);
                        err = -1;
                        goto out;
                }
                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;
                perf_env__fetch_btf(env, info->btf_id, btf);
        }

So we never get into this if body and this do not call
perf__env_fetch_btf() and thus don't write BTF info to the perf.data
header.

And yes, there are BPF programs with BTF information associated:

[root@quaco perf]# bpftool map dump pids_filtered
[{
        "key": 2592,
        "value": true
    },{
        "key": 20511,
        "value": true
    }
]
[root@quaco perf]#

I.e. bpftool can find the BTF info and thus is able to show the
'pids_filtered' map keys and values pretty printed, not just as hex raw
data.

I'm trying to find out why 'bpftool map dump' finds the BTF info while
perf_event__synthesize_one_bpf_prog() doesn't.

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-15 19:06             ` Arnaldo Carvalho de Melo
@ 2019-03-15 19:26               ` Arnaldo Carvalho de Melo
  2019-03-15 19:31                 ` Song Liu
  2019-03-15 19:42                 ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-15 19:26 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf

Em Fri, Mar 15, 2019 at 04:06:51PM -0300, Arnaldo Carvalho de Melo escreveu:
> And yes, there are BPF programs with BTF information associated:
 
> [root@quaco perf]# bpftool map dump pids_filtered
> [{
>         "key": 2592,
>         "value": true
>     },{
>         "key": 20511,
>         "value": true
>     }
> ]
> [root@quaco perf]#
 
> I.e. bpftool can find the BTF info and thus is able to show the
> 'pids_filtered' map keys and values pretty printed, not just as hex raw
> data.
 
> I'm trying to find out why 'bpftool map dump' finds the BTF info while
> perf_event__synthesize_one_bpf_prog() doesn't.

Humm, the BTF info above is for BPF _maps_ not for _programs_, I think
you haven't added BTF info for maps in the perf.data header, right?

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-15 19:26               ` Arnaldo Carvalho de Melo
@ 2019-03-15 19:31                 ` Song Liu
  2019-03-15 19:42                 ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 100+ messages in thread
From: Song Liu @ 2019-03-15 19:31 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf

Sorry for replying from the phone.

Sent from my iPhone

> On Mar 15, 2019, at 12:26 PM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Fri, Mar 15, 2019 at 04:06:51PM -0300, Arnaldo Carvalho de Melo escreveu:
>> And yes, there are BPF programs with BTF information associated:
> 
>> [root@quaco perf]# bpftool map dump pids_filtered
>> [{
>>        "key": 2592,
>>        "value": true
>>    },{
>>        "key": 20511,
>>        "value": true
>>    }
>> ]
>> [root@quaco perf]#
> 
>> I.e. bpftool can find the BTF info and thus is able to show the
>> 'pids_filtered' map keys and values pretty printed, not just as hex raw
>> data.
> 
>> I'm trying to find out why 'bpftool map dump' finds the BTF info while
>> perf_event__synthesize_one_bpf_prog() doesn't.
> 
> Humm, the BTF info above is for BPF _maps_ not for _programs_, I think
> you haven't added BTF info for maps in the perf.data header, right?
> 
> - Arnaldo

That’s right. We iterate all BPF programs, and fetch BTF referred by the programs.

Thanks,
Song

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
  2019-03-15 19:26               ` Arnaldo Carvalho de Melo
  2019-03-15 19:31                 ` Song Liu
@ 2019-03-15 19:42                 ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-15 19:42 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim, sdf

Em Fri, Mar 15, 2019 at 04:26:10PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Mar 15, 2019 at 04:06:51PM -0300, Arnaldo Carvalho de Melo escreveu:
> > And yes, there are BPF programs with BTF information associated:
>  
> > [root@quaco perf]# bpftool map dump pids_filtered
> > [{
> >         "key": 2592,
> >         "value": true
> >     },{
> >         "key": 20511,
> >         "value": true
> >     }
> > ]
> > [root@quaco perf]#
>  
> > I.e. bpftool can find the BTF info and thus is able to show the
> > 'pids_filtered' map keys and values pretty printed, not just as hex raw
> > data.
>  
> > I'm trying to find out why 'bpftool map dump' finds the BTF info while
> > perf_event__synthesize_one_bpf_prog() doesn't.
> 
> Humm, the BTF info above is for BPF _maps_ not for _programs_, I think
> you haven't added BTF info for maps in the perf.data header, right?

And then the BPF program I was using to test this had BTF encoded from
DWARF by pahole, so only associated to BPF maps, not to BPF programs, as
soon as I regenerated that BPF .o with clang 9.0, I got the BTF info for
the BPF programs and all works as expected:

[root@quaco perf]# clang --version
clang version 9.0.0 (https://git.llvm.org/git/clang.git/ 7906282d3afec5dfdc2b27943fd6c0309086c507) (https://git.llvm.org/git/llvm.git/ a1b5de1ff8ae8bc79dc8e86e1f82565229bd0500)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/llvm/bin
[root@quaco perf]# perf record -e /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c sleep 1
LLVM: dumping /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.o
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.023 MB perf.data ]
[root@quaco perf]# file /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.o
/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.o: ELF 64-bit LSB relocatable, eBPF, version 1 (SYSV), with debug_info, not stripped
[root@quaco perf]# readelf -SW /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.o | grep BTF
  [22] .BTF              PROGBITS        0000000000000000 000ede 000b0e 00      0   0  1
  [23] .BTF.ext          PROGBITS        0000000000000000 0019ec 0002a0 00      0   0  1
  [24] .rel.BTF.ext      REL             0000000000000000 002fa8 000270 10     30  23  8
[root@quaco perf]# grep examples ~/.perfconfig
	add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.o
[root@quaco perf]# 
[root@quaco perf]# perf trace -e recvmmsg

Then, while this runs, using that augmented_raw_syscalls.o BPF program
generated with clang 9.0 and with proper BTF for BPF programs and not
just for BPF maps:

[root@quaco ~]# bpftool map dump pids_filtered
[{
        "key": 22459,
        "value": true
    },{
        "key": 2592,
        "value": true
    }
]
[root@quaco ~]#

[root@quaco ~]# perf record sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.020 MB perf.data (7 samples) ]
[root@quaco ~]# perf report --header-only | grep b[pt]f
# event : name = cycles:ppp, , id = { 1116204, 1116205, 1116206, 1116207, 1116208, 1116209, 1116210, 1116211 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1
# bpf_prog_info of id 13
# bpf_prog_info of id 14
# bpf_prog_info of id 15
# bpf_prog_info of id 16
# bpf_prog_info of id 17
# bpf_prog_info of id 18
# bpf_prog_info of id 21
# bpf_prog_info of id 22
# bpf_prog_info of id 51
# bpf_prog_info of id 52
# btf info of id 8
[root@quaco ~]#

Moving along the patch queue...

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
@ 2019-03-18 16:38   ` Arnaldo Carvalho de Melo
  2019-03-18 16:43     ` Arnaldo Carvalho de Melo
  2019-03-19  6:05     ` Song Liu
  2019-03-22 22:42   ` [tip:perf/urgent] perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO tip-bot for Song Liu
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-18 16:38 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
> This patch enables the annotation of bpf program.
> 
> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
> calls into a new function symbol__disassemble_bpf(), where annotation
> line information is filled based bpf_prog_info and btf saved in given
> perf_env.
> 
> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/build/Makefile.feature |   6 +-
>  tools/perf/Makefile.config   |   4 +

I see the changes to these two files, but I can't see the feature test
that it triggers, forgot to do a git-add? Or is it in an upcoming patch
in this series?

After applying this test it "works":

  make: Entering directory '/home/acme/git/perf/tools/perf'
    BUILD:   Doing 'make -j8' parallel build

  Auto-detecting system features:
  ...                         dwarf: [ on  ]
  ...            dwarf_getlocations: [ on  ]
  <SNIP>
  ...                           bpf: [ on  ]
  ...                        libaio: [ on  ]
  ...        disassembler-four-args: [ on  ]

Because you added it to FEATURE_TESTS_BASIC, and this means that if
tools/build/feature/test-all.c builds, then what is in
FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
tools/build/feature/test-all.c, so it works because all the other
features are present.

Take a look at:

  2a07d814747b ("tools build feature: Check if libaio is available")

To see what needs to be done.

Either way, its interesting to break this patch in two, one adding the
feature test and another to use it, i.e. the second patch out of this
should have the commit log message in this patch.

I've applied the patches up to before this one and will continue
processing other patches while you address this.

Thanks,

- Arnaldo

>  tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
>  tools/perf/util/dso.c        |   1 +
>  tools/perf/util/dso.h        |  32 +++++---
>  tools/perf/util/symbol.c     |   1 +
>  6 files changed, 180 insertions(+), 14 deletions(-)
> 
> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> index 61e46d54a67c..8d3864b061f3 100644
> --- a/tools/build/Makefile.feature
> +++ b/tools/build/Makefile.feature
> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
>          sched_getcpu			\
>          sdt				\
>          setns				\
> -        libaio
> +        libaio				\
> +        disassembler-four-args
>  
>  # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
>  # of all feature tests
> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
>           lzma                   \
>           get_cpuid              \
>           bpf			\
> -         libaio
> +         libaio			\
> +         disassembler-four-args
>  
>  # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
>  # If in the future we need per-feature checks/flags for features not
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index df4ad45599ca..c51b59e43dcc 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
>      CFLAGS += -DHAVE_KVM_STAT_SUPPORT
>  endif
>  
> +ifeq ($(feature-disassembler-four-args), 1)
> +    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
> +endif
> +
>  ifeq (${IS_64_BIT}, 1)
>    ifndef NO_PERF_READ_VDSO32
>      $(call feature_check,compile-32)
> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
> index 5f6dbbf5d749..e492b19a157c 100644
> --- a/tools/perf/util/annotate.c
> +++ b/tools/perf/util/annotate.c
> @@ -10,6 +10,10 @@
>  #include <errno.h>
>  #include <inttypes.h>
>  #include <libgen.h>
> +#include <bpf/bpf.h>
> +#include <bpf/btf.h>
> +#include <bpf/libbpf.h>
> +#include <linux/btf.h>
>  #include "util.h"
>  #include "ui/ui.h"
>  #include "sort.h"
> @@ -24,6 +28,7 @@
>  #include "annotate.h"
>  #include "evsel.h"
>  #include "evlist.h"
> +#include "bpf-event.h"
>  #include "block-range.h"
>  #include "string2.h"
>  #include "arch/common.h"
> @@ -31,6 +36,9 @@
>  #include <pthread.h>
>  #include <linux/bitops.h>
>  #include <linux/kernel.h>
> +#include <bfd.h>
> +#include <dis-asm.h>
> +#include <bpf/libbpf.h>
>  
>  /* FIXME: For the HE_COLORSET */
>  #include "ui/browser.h"
> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
>  	return 0;
>  }
>  
> +static int symbol__disassemble_bpf(struct symbol *sym,
> +				   struct annotate_args *args)
> +{
> +	struct annotation *notes = symbol__annotation(sym);
> +	struct annotation_options *opts = args->options;
> +	struct bpf_prog_info_linear *info_linear;
> +	struct bpf_prog_linfo *prog_linfo = NULL;
> +	struct bpf_prog_info_node *info_node;
> +	int len = sym->end - sym->start;
> +	disassembler_ftype disassemble;
> +	struct map *map = args->ms.map;
> +	struct disassemble_info info;
> +	struct dso *dso = map->dso;
> +	int pc = 0, count, sub_id;
> +	struct btf *btf = NULL;
> +	char tpath[PATH_MAX];
> +	size_t buf_size;
> +	int nr_skip = 0;
> +	int ret = -1;
> +	char *buf;
> +	bfd *bfdf;
> +	FILE *s;
> +
> +	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
> +		return -1;
> +
> +	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
> +		 sym->name, sym->start, sym->end - sym->start);
> +
> +	memset(tpath, 0, sizeof(tpath));
> +	perf_exe(tpath, sizeof(tpath));
> +
> +	bfdf = bfd_openr(tpath, NULL);
> +	assert(bfdf);
> +	assert(bfd_check_format(bfdf, bfd_object));
> +
> +	s = open_memstream(&buf, &buf_size);
> +	if (!s)
> +		goto out;
> +	init_disassemble_info(&info, s,
> +			      (fprintf_ftype) fprintf);
> +
> +	info.arch = bfd_get_arch(bfdf);
> +	info.mach = bfd_get_mach(bfdf);
> +
> +	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
> +						 dso->bpf_prog.id);
> +	if (!info_node)
> +		goto out;
> +	info_linear = info_node->info_linear;
> +	sub_id = dso->bpf_prog.sub_id;
> +
> +	info.buffer = (void *)(info_linear->info.jited_prog_insns);
> +	info.buffer_length = info_linear->info.jited_prog_len;
> +
> +	if (info_linear->info.nr_line_info)
> +		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
> +
> +	if (info_linear->info.btf_id) {
> +		struct btf_node *node;
> +
> +		node = perf_env__find_btf(dso->bpf_prog.env,
> +					  info_linear->info.btf_id);
> +		if (node)
> +			btf = btf__new((__u8 *)(node->data),
> +				       node->data_size);
> +	}
> +
> +	disassemble_init_for_target(&info);
> +
> +#ifdef DISASM_FOUR_ARGS_SIGNATURE
> +	disassemble = disassembler(info.arch,
> +				   bfd_big_endian(bfdf),
> +				   info.mach,
> +				   bfdf);
> +#else
> +	disassemble = disassembler(bfdf);
> +#endif
> +	assert(disassemble);
> +
> +	fflush(s);
> +	do {
> +		const struct bpf_line_info *linfo = NULL;
> +		struct disasm_line *dl;
> +		size_t prev_buf_size;
> +		const char *srcline;
> +		u64 addr;
> +
> +		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
> +		count = disassemble(pc, &info);
> +
> +		if (prog_linfo)
> +			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
> +								addr, sub_id,
> +								nr_skip);
> +
> +		if (linfo && btf) {
> +			srcline = btf__name_by_offset(btf, linfo->line_off);
> +			nr_skip++;
> +		} else
> +			srcline = NULL;
> +
> +		fprintf(s, "\n");
> +		prev_buf_size = buf_size;
> +		fflush(s);
> +
> +		if (!opts->hide_src_code && srcline) {
> +			args->offset = -1;
> +			args->line = strdup(srcline);
> +			args->line_nr = 0;
> +			args->ms.sym  = sym;
> +			dl = disasm_line__new(args);
> +			if (dl) {
> +				annotation_line__add(&dl->al,
> +						     &notes->src->source);
> +			}
> +		}
> +
> +		args->offset = pc;
> +		args->line = buf + prev_buf_size;
> +		args->line_nr = 0;
> +		args->ms.sym  = sym;
> +		dl = disasm_line__new(args);
> +		if (dl)
> +			annotation_line__add(&dl->al, &notes->src->source);
> +
> +		pc += count;
> +	} while (count > 0 && pc < len);
> +
> +	ret = 0;
> +out:
> +	free(prog_linfo);
> +	free(btf);
> +	fclose(s);
> +	bfd_close(bfdf);
> +	return ret;
> +}
> +
>  static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
>  {
>  	struct annotation_options *opts = args->options;
> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
>  	pr_debug("annotating [%p] %30s : [%p] %30s\n",
>  		 dso, dso->long_name, sym, sym->name);
>  
> -	if (dso__is_kcore(dso)) {
> +	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
> +		return symbol__disassemble_bpf(sym, args);
> +	} else if (dso__is_kcore(dso)) {
>  		kce.kcore_filename = symfs_filename;
>  		kce.addr = map__rip_2objdump(map, sym->start);
>  		kce.offs = sym->start;
> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> index ba58ba603b69..58547c468c65 100644
> --- a/tools/perf/util/dso.c
> +++ b/tools/perf/util/dso.c
> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
>  	case DSO_BINARY_TYPE__KALLSYMS:
>  	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
>  	case DSO_BINARY_TYPE__JAVA_JIT:
> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
>  	case DSO_BINARY_TYPE__NOT_FOUND:
>  		ret = -1;
>  		break;
> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> index bb417c54c25a..c274b5aa839d 100644
> --- a/tools/perf/util/dso.h
> +++ b/tools/perf/util/dso.h
> @@ -14,6 +14,7 @@
>  
>  struct machine;
>  struct map;
> +struct perf_env;
>  
>  enum dso_binary_type {
>  	DSO_BINARY_TYPE__KALLSYMS = 0,
> @@ -35,6 +36,7 @@ enum dso_binary_type {
>  	DSO_BINARY_TYPE__KCORE,
>  	DSO_BINARY_TYPE__GUEST_KCORE,
>  	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
> +	DSO_BINARY_TYPE__BPF_PROG_INFO,
>  	DSO_BINARY_TYPE__NOT_FOUND,
>  };
>  
> @@ -178,17 +180,25 @@ struct dso {
>  	struct auxtrace_cache *auxtrace_cache;
>  	int		 comp;
>  
> -	/* dso data file */
> -	struct {
> -		struct rb_root	 cache;
> -		int		 fd;
> -		int		 status;
> -		u32		 status_seen;
> -		size_t		 file_size;
> -		struct list_head open_entry;
> -		u64		 debug_frame_offset;
> -		u64		 eh_frame_hdr_offset;
> -	} data;
> +	union {
> +		/* dso data file */
> +		struct {
> +			struct rb_root	 cache;
> +			int		 fd;
> +			int		 status;
> +			u32		 status_seen;
> +			size_t		 file_size;
> +			struct list_head open_entry;
> +			u64		 debug_frame_offset;
> +			u64		 eh_frame_hdr_offset;
> +		} data;
> +		/* bpf prog information */
> +		struct {
> +			u32		id;
> +			u32		sub_id;
> +			struct perf_env	*env;
> +		} bpf_prog;
> +	};
>  
>  	union { /* Tool specific area */
>  		void	 *priv;
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 758bf5f74e6e..4e2e304d4037 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
>  	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
>  		return true;
>  
> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
>  	case DSO_BINARY_TYPE__NOT_FOUND:
>  	default:
>  		return false;
> -- 
> 2.17.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-18 16:38   ` Arnaldo Carvalho de Melo
@ 2019-03-18 16:43     ` Arnaldo Carvalho de Melo
  2019-03-19  6:10       ` Song Liu
  2019-03-19  6:05     ` Song Liu
  1 sibling, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-18 16:43 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
> > This patch enables the annotation of bpf program.
> > 
> > A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
> > programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
> > calls into a new function symbol__disassemble_bpf(), where annotation
> > line information is filled based bpf_prog_info and btf saved in given
> > perf_env.
> > 
> > symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
> > 
> > Signed-off-by: Song Liu <songliubraving@fb.com>
> > ---
> >  tools/build/Makefile.feature |   6 +-
> >  tools/perf/Makefile.config   |   4 +
> 
> I see the changes to these two files, but I can't see the feature test
> that it triggers, forgot to do a git-add? Or is it in an upcoming patch
> in this series?
> 
> After applying this test it "works":
> 
>   make: Entering directory '/home/acme/git/perf/tools/perf'
>     BUILD:   Doing 'make -j8' parallel build
> 
>   Auto-detecting system features:
>   ...                         dwarf: [ on  ]
>   ...            dwarf_getlocations: [ on  ]
>   <SNIP>
>   ...                           bpf: [ on  ]
>   ...                        libaio: [ on  ]
>   ...        disassembler-four-args: [ on  ]
> 
> Because you added it to FEATURE_TESTS_BASIC, and this means that if
> tools/build/feature/test-all.c builds, then what is in
> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> tools/build/feature/test-all.c, so it works because all the other
> features are present.
> 
> Take a look at:
> 
>   2a07d814747b ("tools build feature: Check if libaio is available")
> 
> To see what needs to be done.
> 
> Either way, its interesting to break this patch in two, one adding the
> feature test and another to use it, i.e. the second patch out of this
> should have the commit log message in this patch.
> 
> I've applied the patches up to before this one and will continue
> processing other patches while you address this.

Ok, to continue processing the other patches I chunked out the part
below into a 3rd patch from the above one and have it applied already.

commit f326de312abc3657b0397817c66cd7e1540655f7
Author: Song Liu <songliubraving@fb.com>
Date:   Mon Mar 11 22:30:48 2019 -0700

    perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO
    
    Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In
    symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new
    function symbol__disassemble_bpf() in an upcoming patch, where annotation line
    information is filled based bpf_prog_info and btf saved in given perf_env.
    
    Signed-off-by: Song Liu <songliubraving@fb.com>
    Reviewed-by: Jiri Olsa <jolsa@kernel.org>
    Cc: Alexei Starovoitov <ast@kernel.org>
    Cc: Daniel Borkmann <daniel@iogearbox.net>
    Cc: Namhyung Kim <namhyung@kernel.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Stanislav Fomichev <sdf@google.com>
    Cc: kernel-team@fb.com
    Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
    [ split from a larger patch ]
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index ba58ba603b69..58547c468c65 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	case DSO_BINARY_TYPE__KALLSYMS:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
 	case DSO_BINARY_TYPE__JAVA_JIT:
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
 		break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index bb417c54c25a..c274b5aa839d 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,7 @@
 
 struct machine;
 struct map;
+struct perf_env;
 
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -35,6 +36,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BPF_PROG_INFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
@@ -178,17 +180,25 @@ struct dso {
 	struct auxtrace_cache *auxtrace_cache;
 	int		 comp;
 
-	/* dso data file */
-	struct {
-		struct rb_root	 cache;
-		int		 fd;
-		int		 status;
-		u32		 status_seen;
-		size_t		 file_size;
-		struct list_head open_entry;
-		u64		 debug_frame_offset;
-		u64		 eh_frame_hdr_offset;
-	} data;
+	union {
+		/* dso data file */
+		struct {
+			struct rb_root	 cache;
+			int		 fd;
+			int		 status;
+			u32		 status_seen;
+			size_t		 file_size;
+			struct list_head open_entry;
+			u64		 debug_frame_offset;
+			u64		 eh_frame_hdr_offset;
+		} data;
+		/* bpf prog information */
+		struct {
+			u32		id;
+			u32		sub_id;
+			struct perf_env	*env;
+		} bpf_prog;
+	};
 
 	union { /* Tool specific area */
 		void	 *priv;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 58442ca5e3c4..5cbad55cd99d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
 		return true;
 
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 	default:
 		return false;

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-18 16:38   ` Arnaldo Carvalho de Melo
  2019-03-18 16:43     ` Arnaldo Carvalho de Melo
@ 2019-03-19  6:05     ` Song Liu
  2019-03-19 13:37       ` Arnaldo Carvalho de Melo
  2019-03-19 13:58       ` Arnaldo Carvalho de Melo
  1 sibling, 2 replies; 100+ messages in thread
From: Song Liu @ 2019-03-19  6:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Sorry for the late response. 

> On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
>> This patch enables the annotation of bpf program.
>> 
>> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
>> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
>> calls into a new function symbol__disassemble_bpf(), where annotation
>> line information is filled based bpf_prog_info and btf saved in given
>> perf_env.
>> 
>> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
>> 
>> Signed-off-by: Song Liu <songliubraving@fb.com>
>> ---
>> tools/build/Makefile.feature |   6 +-
>> tools/perf/Makefile.config   |   4 +
> 
> I see the changes to these two files, but I can't see the feature test
> that it triggers, forgot to do a git-add? Or is it in an upcoming patch
> in this series?

test-disassembler-four-args.c is an existing test used by bpftool.
It was added in fb982666e380c1632a74495b68b3c33a66e76430 .  

> 
> After applying this test it "works":
> 
>  make: Entering directory '/home/acme/git/perf/tools/perf'
>    BUILD:   Doing 'make -j8' parallel build
> 
>  Auto-detecting system features:
>  ...                         dwarf: [ on  ]
>  ...            dwarf_getlocations: [ on  ]
>  <SNIP>
>  ...                           bpf: [ on  ]
>  ...                        libaio: [ on  ]
>  ...        disassembler-four-args: [ on  ]
> 
> Because you added it to FEATURE_TESTS_BASIC, and this means that if
> tools/build/feature/test-all.c builds, then what is in
> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> tools/build/feature/test-all.c, so it works because all the other
> features are present.
> 
> Take a look at:
> 
>  2a07d814747b ("tools build feature: Check if libaio is available")
> 
> To see what needs to be done.

I used different versions of gcc to verify that current version of the 
patch works for both test-succeed and test-fail cases. I guess something 
like the following is needed? But the test does work without it. 

Thanks,
Song


diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c
index e903b86b742f..7853e6d91090 100644
--- i/tools/build/feature/test-all.c
+++ w/tools/build/feature/test-all.c
@@ -178,6 +178,10 @@
 # include "test-reallocarray.c"
 #undef main

+#define main main_test_disassembler_four_args
+# include "test-disassembler-four-args.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
        main_test_libpython();
@@ -219,6 +223,7 @@ int main(int argc, char *argv[])
        main_test_setns();
        main_test_libaio();
        main_test_reallocarray();
+       main_test_disassembler_four_args();

        return 0;
 }


> 
> Either way, its interesting to break this patch in two, one adding the
> feature test and another to use it, i.e. the second patch out of this
> should have the commit log message in this patch.
> 
> I've applied the patches up to before this one and will continue
> processing other patches while you address this.
> 
> Thanks,
> 
> - Arnaldo
> 
>> tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
>> tools/perf/util/dso.c        |   1 +
>> tools/perf/util/dso.h        |  32 +++++---
>> tools/perf/util/symbol.c     |   1 +
>> 6 files changed, 180 insertions(+), 14 deletions(-)
>> 
>> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
>> index 61e46d54a67c..8d3864b061f3 100644
>> --- a/tools/build/Makefile.feature
>> +++ b/tools/build/Makefile.feature
>> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
>>         sched_getcpu			\
>>         sdt				\
>>         setns				\
>> -        libaio
>> +        libaio				\
>> +        disassembler-four-args
>> 
>> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
>> # of all feature tests
>> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
>>          lzma                   \
>>          get_cpuid              \
>>          bpf			\
>> -         libaio
>> +         libaio			\
>> +         disassembler-four-args
>> 
>> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
>> # If in the future we need per-feature checks/flags for features not
>> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
>> index df4ad45599ca..c51b59e43dcc 100644
>> --- a/tools/perf/Makefile.config
>> +++ b/tools/perf/Makefile.config
>> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
>>     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
>> endif
>> 
>> +ifeq ($(feature-disassembler-four-args), 1)
>> +    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
>> +endif
>> +
>> ifeq (${IS_64_BIT}, 1)
>>   ifndef NO_PERF_READ_VDSO32
>>     $(call feature_check,compile-32)
>> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
>> index 5f6dbbf5d749..e492b19a157c 100644
>> --- a/tools/perf/util/annotate.c
>> +++ b/tools/perf/util/annotate.c
>> @@ -10,6 +10,10 @@
>> #include <errno.h>
>> #include <inttypes.h>
>> #include <libgen.h>
>> +#include <bpf/bpf.h>
>> +#include <bpf/btf.h>
>> +#include <bpf/libbpf.h>
>> +#include <linux/btf.h>
>> #include "util.h"
>> #include "ui/ui.h"
>> #include "sort.h"
>> @@ -24,6 +28,7 @@
>> #include "annotate.h"
>> #include "evsel.h"
>> #include "evlist.h"
>> +#include "bpf-event.h"
>> #include "block-range.h"
>> #include "string2.h"
>> #include "arch/common.h"
>> @@ -31,6 +36,9 @@
>> #include <pthread.h>
>> #include <linux/bitops.h>
>> #include <linux/kernel.h>
>> +#include <bfd.h>
>> +#include <dis-asm.h>
>> +#include <bpf/libbpf.h>
>> 
>> /* FIXME: For the HE_COLORSET */
>> #include "ui/browser.h"
>> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
>> 	return 0;
>> }
>> 
>> +static int symbol__disassemble_bpf(struct symbol *sym,
>> +				   struct annotate_args *args)
>> +{
>> +	struct annotation *notes = symbol__annotation(sym);
>> +	struct annotation_options *opts = args->options;
>> +	struct bpf_prog_info_linear *info_linear;
>> +	struct bpf_prog_linfo *prog_linfo = NULL;
>> +	struct bpf_prog_info_node *info_node;
>> +	int len = sym->end - sym->start;
>> +	disassembler_ftype disassemble;
>> +	struct map *map = args->ms.map;
>> +	struct disassemble_info info;
>> +	struct dso *dso = map->dso;
>> +	int pc = 0, count, sub_id;
>> +	struct btf *btf = NULL;
>> +	char tpath[PATH_MAX];
>> +	size_t buf_size;
>> +	int nr_skip = 0;
>> +	int ret = -1;
>> +	char *buf;
>> +	bfd *bfdf;
>> +	FILE *s;
>> +
>> +	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
>> +		return -1;
>> +
>> +	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
>> +		 sym->name, sym->start, sym->end - sym->start);
>> +
>> +	memset(tpath, 0, sizeof(tpath));
>> +	perf_exe(tpath, sizeof(tpath));
>> +
>> +	bfdf = bfd_openr(tpath, NULL);
>> +	assert(bfdf);
>> +	assert(bfd_check_format(bfdf, bfd_object));
>> +
>> +	s = open_memstream(&buf, &buf_size);
>> +	if (!s)
>> +		goto out;
>> +	init_disassemble_info(&info, s,
>> +			      (fprintf_ftype) fprintf);
>> +
>> +	info.arch = bfd_get_arch(bfdf);
>> +	info.mach = bfd_get_mach(bfdf);
>> +
>> +	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
>> +						 dso->bpf_prog.id);
>> +	if (!info_node)
>> +		goto out;
>> +	info_linear = info_node->info_linear;
>> +	sub_id = dso->bpf_prog.sub_id;
>> +
>> +	info.buffer = (void *)(info_linear->info.jited_prog_insns);
>> +	info.buffer_length = info_linear->info.jited_prog_len;
>> +
>> +	if (info_linear->info.nr_line_info)
>> +		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
>> +
>> +	if (info_linear->info.btf_id) {
>> +		struct btf_node *node;
>> +
>> +		node = perf_env__find_btf(dso->bpf_prog.env,
>> +					  info_linear->info.btf_id);
>> +		if (node)
>> +			btf = btf__new((__u8 *)(node->data),
>> +				       node->data_size);
>> +	}
>> +
>> +	disassemble_init_for_target(&info);
>> +
>> +#ifdef DISASM_FOUR_ARGS_SIGNATURE
>> +	disassemble = disassembler(info.arch,
>> +				   bfd_big_endian(bfdf),
>> +				   info.mach,
>> +				   bfdf);
>> +#else
>> +	disassemble = disassembler(bfdf);
>> +#endif
>> +	assert(disassemble);
>> +
>> +	fflush(s);
>> +	do {
>> +		const struct bpf_line_info *linfo = NULL;
>> +		struct disasm_line *dl;
>> +		size_t prev_buf_size;
>> +		const char *srcline;
>> +		u64 addr;
>> +
>> +		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
>> +		count = disassemble(pc, &info);
>> +
>> +		if (prog_linfo)
>> +			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
>> +								addr, sub_id,
>> +								nr_skip);
>> +
>> +		if (linfo && btf) {
>> +			srcline = btf__name_by_offset(btf, linfo->line_off);
>> +			nr_skip++;
>> +		} else
>> +			srcline = NULL;
>> +
>> +		fprintf(s, "\n");
>> +		prev_buf_size = buf_size;
>> +		fflush(s);
>> +
>> +		if (!opts->hide_src_code && srcline) {
>> +			args->offset = -1;
>> +			args->line = strdup(srcline);
>> +			args->line_nr = 0;
>> +			args->ms.sym  = sym;
>> +			dl = disasm_line__new(args);
>> +			if (dl) {
>> +				annotation_line__add(&dl->al,
>> +						     &notes->src->source);
>> +			}
>> +		}
>> +
>> +		args->offset = pc;
>> +		args->line = buf + prev_buf_size;
>> +		args->line_nr = 0;
>> +		args->ms.sym  = sym;
>> +		dl = disasm_line__new(args);
>> +		if (dl)
>> +			annotation_line__add(&dl->al, &notes->src->source);
>> +
>> +		pc += count;
>> +	} while (count > 0 && pc < len);
>> +
>> +	ret = 0;
>> +out:
>> +	free(prog_linfo);
>> +	free(btf);
>> +	fclose(s);
>> +	bfd_close(bfdf);
>> +	return ret;
>> +}
>> +
>> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
>> {
>> 	struct annotation_options *opts = args->options;
>> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
>> 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
>> 		 dso, dso->long_name, sym, sym->name);
>> 
>> -	if (dso__is_kcore(dso)) {
>> +	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
>> +		return symbol__disassemble_bpf(sym, args);
>> +	} else if (dso__is_kcore(dso)) {
>> 		kce.kcore_filename = symfs_filename;
>> 		kce.addr = map__rip_2objdump(map, sym->start);
>> 		kce.offs = sym->start;
>> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
>> index ba58ba603b69..58547c468c65 100644
>> --- a/tools/perf/util/dso.c
>> +++ b/tools/perf/util/dso.c
>> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
>> 	case DSO_BINARY_TYPE__KALLSYMS:
>> 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
>> 	case DSO_BINARY_TYPE__JAVA_JIT:
>> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
>> 	case DSO_BINARY_TYPE__NOT_FOUND:
>> 		ret = -1;
>> 		break;
>> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
>> index bb417c54c25a..c274b5aa839d 100644
>> --- a/tools/perf/util/dso.h
>> +++ b/tools/perf/util/dso.h
>> @@ -14,6 +14,7 @@
>> 
>> struct machine;
>> struct map;
>> +struct perf_env;
>> 
>> enum dso_binary_type {
>> 	DSO_BINARY_TYPE__KALLSYMS = 0,
>> @@ -35,6 +36,7 @@ enum dso_binary_type {
>> 	DSO_BINARY_TYPE__KCORE,
>> 	DSO_BINARY_TYPE__GUEST_KCORE,
>> 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
>> +	DSO_BINARY_TYPE__BPF_PROG_INFO,
>> 	DSO_BINARY_TYPE__NOT_FOUND,
>> };
>> 
>> @@ -178,17 +180,25 @@ struct dso {
>> 	struct auxtrace_cache *auxtrace_cache;
>> 	int		 comp;
>> 
>> -	/* dso data file */
>> -	struct {
>> -		struct rb_root	 cache;
>> -		int		 fd;
>> -		int		 status;
>> -		u32		 status_seen;
>> -		size_t		 file_size;
>> -		struct list_head open_entry;
>> -		u64		 debug_frame_offset;
>> -		u64		 eh_frame_hdr_offset;
>> -	} data;
>> +	union {
>> +		/* dso data file */
>> +		struct {
>> +			struct rb_root	 cache;
>> +			int		 fd;
>> +			int		 status;
>> +			u32		 status_seen;
>> +			size_t		 file_size;
>> +			struct list_head open_entry;
>> +			u64		 debug_frame_offset;
>> +			u64		 eh_frame_hdr_offset;
>> +		} data;
>> +		/* bpf prog information */
>> +		struct {
>> +			u32		id;
>> +			u32		sub_id;
>> +			struct perf_env	*env;
>> +		} bpf_prog;
>> +	};
>> 
>> 	union { /* Tool specific area */
>> 		void	 *priv;
>> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
>> index 758bf5f74e6e..4e2e304d4037 100644
>> --- a/tools/perf/util/symbol.c
>> +++ b/tools/perf/util/symbol.c
>> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
>> 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
>> 		return true;
>> 
>> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
>> 	case DSO_BINARY_TYPE__NOT_FOUND:
>> 	default:
>> 		return false;
>> -- 
>> 2.17.1
> 
> -- 
> 
> - Arnaldo


^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-18 16:43     ` Arnaldo Carvalho de Melo
@ 2019-03-19  6:10       ` Song Liu
  2019-03-19 13:37         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-19  6:10 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, ast, daniel, Kernel Team, peterz,
	acme, jolsa, namhyung, sdf



> On Mar 18, 2019, at 9:43 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu:
>> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
>>> This patch enables the annotation of bpf program.
>>> 
>>> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
>>> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
>>> calls into a new function symbol__disassemble_bpf(), where annotation
>>> line information is filled based bpf_prog_info and btf saved in given
>>> perf_env.
>>> 
>>> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
>>> 
>>> Signed-off-by: Song Liu <songliubraving@fb.com>
>>> ---
>>> tools/build/Makefile.feature |   6 +-
>>> tools/perf/Makefile.config   |   4 +
>> 
>> I see the changes to these two files, but I can't see the feature test
>> that it triggers, forgot to do a git-add? Or is it in an upcoming patch
>> in this series?
>> 
>> After applying this test it "works":
>> 
>>  make: Entering directory '/home/acme/git/perf/tools/perf'
>>    BUILD:   Doing 'make -j8' parallel build
>> 
>>  Auto-detecting system features:
>>  ...                         dwarf: [ on  ]
>>  ...            dwarf_getlocations: [ on  ]
>>  <SNIP>
>>  ...                           bpf: [ on  ]
>>  ...                        libaio: [ on  ]
>>  ...        disassembler-four-args: [ on  ]
>> 
>> Because you added it to FEATURE_TESTS_BASIC, and this means that if
>> tools/build/feature/test-all.c builds, then what is in
>> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
>> tools/build/feature/test-all.c, so it works because all the other
>> features are present.
>> 
>> Take a look at:
>> 
>>  2a07d814747b ("tools build feature: Check if libaio is available")
>> 
>> To see what needs to be done.
>> 
>> Either way, its interesting to break this patch in two, one adding the
>> feature test and another to use it, i.e. the second patch out of this
>> should have the commit log message in this patch.
>> 
>> I've applied the patches up to before this one and will continue
>> processing other patches while you address this.
> 
> Ok, to continue processing the other patches I chunked out the part
> below into a 3rd patch from the above one and have it applied already.

Could you please push applied patches to the tmp.perf/bpf-annotation 
branch? 

Thanks,
Song

> 
> commit f326de312abc3657b0397817c66cd7e1540655f7
> Author: Song Liu <songliubraving@fb.com>
> Date:   Mon Mar 11 22:30:48 2019 -0700
> 
>    perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO
> 
>    Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In
>    symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new
>    function symbol__disassemble_bpf() in an upcoming patch, where annotation line
>    information is filled based bpf_prog_info and btf saved in given perf_env.
> 
>    Signed-off-by: Song Liu <songliubraving@fb.com>
>    Reviewed-by: Jiri Olsa <jolsa@kernel.org>
>    Cc: Alexei Starovoitov <ast@kernel.org>
>    Cc: Daniel Borkmann <daniel@iogearbox.net>
>    Cc: Namhyung Kim <namhyung@kernel.org>
>    Cc: Peter Zijlstra <peterz@infradead.org>
>    Cc: Stanislav Fomichev <sdf@google.com>
>    Cc: kernel-team@fb.com
>    Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
>    [ split from a larger patch ]
>    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> 
> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> index ba58ba603b69..58547c468c65 100644
> --- a/tools/perf/util/dso.c
> +++ b/tools/perf/util/dso.c
> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
> 	case DSO_BINARY_TYPE__KALLSYMS:
> 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
> 	case DSO_BINARY_TYPE__JAVA_JIT:
> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> 	case DSO_BINARY_TYPE__NOT_FOUND:
> 		ret = -1;
> 		break;
> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> index bb417c54c25a..c274b5aa839d 100644
> --- a/tools/perf/util/dso.h
> +++ b/tools/perf/util/dso.h
> @@ -14,6 +14,7 @@
> 
> struct machine;
> struct map;
> +struct perf_env;
> 
> enum dso_binary_type {
> 	DSO_BINARY_TYPE__KALLSYMS = 0,
> @@ -35,6 +36,7 @@ enum dso_binary_type {
> 	DSO_BINARY_TYPE__KCORE,
> 	DSO_BINARY_TYPE__GUEST_KCORE,
> 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
> +	DSO_BINARY_TYPE__BPF_PROG_INFO,
> 	DSO_BINARY_TYPE__NOT_FOUND,
> };
> 
> @@ -178,17 +180,25 @@ struct dso {
> 	struct auxtrace_cache *auxtrace_cache;
> 	int		 comp;
> 
> -	/* dso data file */
> -	struct {
> -		struct rb_root	 cache;
> -		int		 fd;
> -		int		 status;
> -		u32		 status_seen;
> -		size_t		 file_size;
> -		struct list_head open_entry;
> -		u64		 debug_frame_offset;
> -		u64		 eh_frame_hdr_offset;
> -	} data;
> +	union {
> +		/* dso data file */
> +		struct {
> +			struct rb_root	 cache;
> +			int		 fd;
> +			int		 status;
> +			u32		 status_seen;
> +			size_t		 file_size;
> +			struct list_head open_entry;
> +			u64		 debug_frame_offset;
> +			u64		 eh_frame_hdr_offset;
> +		} data;
> +		/* bpf prog information */
> +		struct {
> +			u32		id;
> +			u32		sub_id;
> +			struct perf_env	*env;
> +		} bpf_prog;
> +	};
> 
> 	union { /* Tool specific area */
> 		void	 *priv;
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 58442ca5e3c4..5cbad55cd99d 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
> 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
> 		return true;
> 
> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> 	case DSO_BINARY_TYPE__NOT_FOUND:
> 	default:
> 		return false;


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19  6:05     ` Song Liu
@ 2019-03-19 13:37       ` Arnaldo Carvalho de Melo
  2019-03-19 13:58       ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 13:37 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu:
> Sorry for the late response. 
> 
> > On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > 
> > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
> >> This patch enables the annotation of bpf program.
> >> 
> >> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
> >> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
> >> calls into a new function symbol__disassemble_bpf(), where annotation
> >> line information is filled based bpf_prog_info and btf saved in given
> >> perf_env.
> >> 
> >> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
> >> 
> >> Signed-off-by: Song Liu <songliubraving@fb.com>
> >> ---
> >> tools/build/Makefile.feature |   6 +-
> >> tools/perf/Makefile.config   |   4 +
> > 
> > I see the changes to these two files, but I can't see the feature test
> > that it triggers, forgot to do a git-add? Or is it in an upcoming patch
> > in this series?
> 
> test-disassembler-four-args.c is an existing test used by bpftool.
> It was added in fb982666e380c1632a74495b68b3c33a66e76430 .  

Ok, I'll add that to the commit log message, but see below
 
> > 
> > After applying this test it "works":
> > 
> >  make: Entering directory '/home/acme/git/perf/tools/perf'
> >    BUILD:   Doing 'make -j8' parallel build
> > 
> >  Auto-detecting system features:
> >  ...                         dwarf: [ on  ]
> >  ...            dwarf_getlocations: [ on  ]
> >  <SNIP>
> >  ...                           bpf: [ on  ]
> >  ...                        libaio: [ on  ]
> >  ...        disassembler-four-args: [ on  ]
> > 
> > Because you added it to FEATURE_TESTS_BASIC, and this means that if
> > tools/build/feature/test-all.c builds, then what is in
> > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> > tools/build/feature/test-all.c, so it works because all the other
> > features are present.
> > 
> > Take a look at:
> > 
> >  2a07d814747b ("tools build feature: Check if libaio is available")
> > 
> > To see what needs to be done.
> 
> I used different versions of gcc to verify that current version of the 
> patch works for both test-succeed and test-fail cases. I guess something 
> like the following is needed? But the test does work without it. 

The following is definetely needed, otherwise if all the other tests in
test-all.c works, this disassembler-four-args feature test will never be
performed.

- Arnaldo
 
> diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c
> index e903b86b742f..7853e6d91090 100644
> --- i/tools/build/feature/test-all.c
> +++ w/tools/build/feature/test-all.c
> @@ -178,6 +178,10 @@
>  # include "test-reallocarray.c"
>  #undef main
> 
> +#define main main_test_disassembler_four_args
> +# include "test-disassembler-four-args.c"
> +#undef main
> +
>  int main(int argc, char *argv[])
>  {
>         main_test_libpython();
> @@ -219,6 +223,7 @@ int main(int argc, char *argv[])
>         main_test_setns();
>         main_test_libaio();
>         main_test_reallocarray();
> +       main_test_disassembler_four_args();
> 
>         return 0;
>  }
> 
> 
> > 
> > Either way, its interesting to break this patch in two, one adding the
> > feature test and another to use it, i.e. the second patch out of this
> > should have the commit log message in this patch.
> > 
> > I've applied the patches up to before this one and will continue
> > processing other patches while you address this.
> > 
> > Thanks,
> > 
> > - Arnaldo
> > 
> >> tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
> >> tools/perf/util/dso.c        |   1 +
> >> tools/perf/util/dso.h        |  32 +++++---
> >> tools/perf/util/symbol.c     |   1 +
> >> 6 files changed, 180 insertions(+), 14 deletions(-)
> >> 
> >> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> >> index 61e46d54a67c..8d3864b061f3 100644
> >> --- a/tools/build/Makefile.feature
> >> +++ b/tools/build/Makefile.feature
> >> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
> >>         sched_getcpu			\
> >>         sdt				\
> >>         setns				\
> >> -        libaio
> >> +        libaio				\
> >> +        disassembler-four-args
> >> 
> >> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
> >> # of all feature tests
> >> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
> >>          lzma                   \
> >>          get_cpuid              \
> >>          bpf			\
> >> -         libaio
> >> +         libaio			\
> >> +         disassembler-four-args
> >> 
> >> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
> >> # If in the future we need per-feature checks/flags for features not
> >> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> >> index df4ad45599ca..c51b59e43dcc 100644
> >> --- a/tools/perf/Makefile.config
> >> +++ b/tools/perf/Makefile.config
> >> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
> >>     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
> >> endif
> >> 
> >> +ifeq ($(feature-disassembler-four-args), 1)
> >> +    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
> >> +endif
> >> +
> >> ifeq (${IS_64_BIT}, 1)
> >>   ifndef NO_PERF_READ_VDSO32
> >>     $(call feature_check,compile-32)
> >> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
> >> index 5f6dbbf5d749..e492b19a157c 100644
> >> --- a/tools/perf/util/annotate.c
> >> +++ b/tools/perf/util/annotate.c
> >> @@ -10,6 +10,10 @@
> >> #include <errno.h>
> >> #include <inttypes.h>
> >> #include <libgen.h>
> >> +#include <bpf/bpf.h>
> >> +#include <bpf/btf.h>
> >> +#include <bpf/libbpf.h>
> >> +#include <linux/btf.h>
> >> #include "util.h"
> >> #include "ui/ui.h"
> >> #include "sort.h"
> >> @@ -24,6 +28,7 @@
> >> #include "annotate.h"
> >> #include "evsel.h"
> >> #include "evlist.h"
> >> +#include "bpf-event.h"
> >> #include "block-range.h"
> >> #include "string2.h"
> >> #include "arch/common.h"
> >> @@ -31,6 +36,9 @@
> >> #include <pthread.h>
> >> #include <linux/bitops.h>
> >> #include <linux/kernel.h>
> >> +#include <bfd.h>
> >> +#include <dis-asm.h>
> >> +#include <bpf/libbpf.h>
> >> 
> >> /* FIXME: For the HE_COLORSET */
> >> #include "ui/browser.h"
> >> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
> >> 	return 0;
> >> }
> >> 
> >> +static int symbol__disassemble_bpf(struct symbol *sym,
> >> +				   struct annotate_args *args)
> >> +{
> >> +	struct annotation *notes = symbol__annotation(sym);
> >> +	struct annotation_options *opts = args->options;
> >> +	struct bpf_prog_info_linear *info_linear;
> >> +	struct bpf_prog_linfo *prog_linfo = NULL;
> >> +	struct bpf_prog_info_node *info_node;
> >> +	int len = sym->end - sym->start;
> >> +	disassembler_ftype disassemble;
> >> +	struct map *map = args->ms.map;
> >> +	struct disassemble_info info;
> >> +	struct dso *dso = map->dso;
> >> +	int pc = 0, count, sub_id;
> >> +	struct btf *btf = NULL;
> >> +	char tpath[PATH_MAX];
> >> +	size_t buf_size;
> >> +	int nr_skip = 0;
> >> +	int ret = -1;
> >> +	char *buf;
> >> +	bfd *bfdf;
> >> +	FILE *s;
> >> +
> >> +	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
> >> +		return -1;
> >> +
> >> +	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
> >> +		 sym->name, sym->start, sym->end - sym->start);
> >> +
> >> +	memset(tpath, 0, sizeof(tpath));
> >> +	perf_exe(tpath, sizeof(tpath));
> >> +
> >> +	bfdf = bfd_openr(tpath, NULL);
> >> +	assert(bfdf);
> >> +	assert(bfd_check_format(bfdf, bfd_object));
> >> +
> >> +	s = open_memstream(&buf, &buf_size);
> >> +	if (!s)
> >> +		goto out;
> >> +	init_disassemble_info(&info, s,
> >> +			      (fprintf_ftype) fprintf);
> >> +
> >> +	info.arch = bfd_get_arch(bfdf);
> >> +	info.mach = bfd_get_mach(bfdf);
> >> +
> >> +	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
> >> +						 dso->bpf_prog.id);
> >> +	if (!info_node)
> >> +		goto out;
> >> +	info_linear = info_node->info_linear;
> >> +	sub_id = dso->bpf_prog.sub_id;
> >> +
> >> +	info.buffer = (void *)(info_linear->info.jited_prog_insns);
> >> +	info.buffer_length = info_linear->info.jited_prog_len;
> >> +
> >> +	if (info_linear->info.nr_line_info)
> >> +		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
> >> +
> >> +	if (info_linear->info.btf_id) {
> >> +		struct btf_node *node;
> >> +
> >> +		node = perf_env__find_btf(dso->bpf_prog.env,
> >> +					  info_linear->info.btf_id);
> >> +		if (node)
> >> +			btf = btf__new((__u8 *)(node->data),
> >> +				       node->data_size);
> >> +	}
> >> +
> >> +	disassemble_init_for_target(&info);
> >> +
> >> +#ifdef DISASM_FOUR_ARGS_SIGNATURE
> >> +	disassemble = disassembler(info.arch,
> >> +				   bfd_big_endian(bfdf),
> >> +				   info.mach,
> >> +				   bfdf);
> >> +#else
> >> +	disassemble = disassembler(bfdf);
> >> +#endif
> >> +	assert(disassemble);
> >> +
> >> +	fflush(s);
> >> +	do {
> >> +		const struct bpf_line_info *linfo = NULL;
> >> +		struct disasm_line *dl;
> >> +		size_t prev_buf_size;
> >> +		const char *srcline;
> >> +		u64 addr;
> >> +
> >> +		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
> >> +		count = disassemble(pc, &info);
> >> +
> >> +		if (prog_linfo)
> >> +			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
> >> +								addr, sub_id,
> >> +								nr_skip);
> >> +
> >> +		if (linfo && btf) {
> >> +			srcline = btf__name_by_offset(btf, linfo->line_off);
> >> +			nr_skip++;
> >> +		} else
> >> +			srcline = NULL;
> >> +
> >> +		fprintf(s, "\n");
> >> +		prev_buf_size = buf_size;
> >> +		fflush(s);
> >> +
> >> +		if (!opts->hide_src_code && srcline) {
> >> +			args->offset = -1;
> >> +			args->line = strdup(srcline);
> >> +			args->line_nr = 0;
> >> +			args->ms.sym  = sym;
> >> +			dl = disasm_line__new(args);
> >> +			if (dl) {
> >> +				annotation_line__add(&dl->al,
> >> +						     &notes->src->source);
> >> +			}
> >> +		}
> >> +
> >> +		args->offset = pc;
> >> +		args->line = buf + prev_buf_size;
> >> +		args->line_nr = 0;
> >> +		args->ms.sym  = sym;
> >> +		dl = disasm_line__new(args);
> >> +		if (dl)
> >> +			annotation_line__add(&dl->al, &notes->src->source);
> >> +
> >> +		pc += count;
> >> +	} while (count > 0 && pc < len);
> >> +
> >> +	ret = 0;
> >> +out:
> >> +	free(prog_linfo);
> >> +	free(btf);
> >> +	fclose(s);
> >> +	bfd_close(bfdf);
> >> +	return ret;
> >> +}
> >> +
> >> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
> >> {
> >> 	struct annotation_options *opts = args->options;
> >> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
> >> 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
> >> 		 dso, dso->long_name, sym, sym->name);
> >> 
> >> -	if (dso__is_kcore(dso)) {
> >> +	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
> >> +		return symbol__disassemble_bpf(sym, args);
> >> +	} else if (dso__is_kcore(dso)) {
> >> 		kce.kcore_filename = symfs_filename;
> >> 		kce.addr = map__rip_2objdump(map, sym->start);
> >> 		kce.offs = sym->start;
> >> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> >> index ba58ba603b69..58547c468c65 100644
> >> --- a/tools/perf/util/dso.c
> >> +++ b/tools/perf/util/dso.c
> >> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
> >> 	case DSO_BINARY_TYPE__KALLSYMS:
> >> 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
> >> 	case DSO_BINARY_TYPE__JAVA_JIT:
> >> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> >> 	case DSO_BINARY_TYPE__NOT_FOUND:
> >> 		ret = -1;
> >> 		break;
> >> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> >> index bb417c54c25a..c274b5aa839d 100644
> >> --- a/tools/perf/util/dso.h
> >> +++ b/tools/perf/util/dso.h
> >> @@ -14,6 +14,7 @@
> >> 
> >> struct machine;
> >> struct map;
> >> +struct perf_env;
> >> 
> >> enum dso_binary_type {
> >> 	DSO_BINARY_TYPE__KALLSYMS = 0,
> >> @@ -35,6 +36,7 @@ enum dso_binary_type {
> >> 	DSO_BINARY_TYPE__KCORE,
> >> 	DSO_BINARY_TYPE__GUEST_KCORE,
> >> 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
> >> +	DSO_BINARY_TYPE__BPF_PROG_INFO,
> >> 	DSO_BINARY_TYPE__NOT_FOUND,
> >> };
> >> 
> >> @@ -178,17 +180,25 @@ struct dso {
> >> 	struct auxtrace_cache *auxtrace_cache;
> >> 	int		 comp;
> >> 
> >> -	/* dso data file */
> >> -	struct {
> >> -		struct rb_root	 cache;
> >> -		int		 fd;
> >> -		int		 status;
> >> -		u32		 status_seen;
> >> -		size_t		 file_size;
> >> -		struct list_head open_entry;
> >> -		u64		 debug_frame_offset;
> >> -		u64		 eh_frame_hdr_offset;
> >> -	} data;
> >> +	union {
> >> +		/* dso data file */
> >> +		struct {
> >> +			struct rb_root	 cache;
> >> +			int		 fd;
> >> +			int		 status;
> >> +			u32		 status_seen;
> >> +			size_t		 file_size;
> >> +			struct list_head open_entry;
> >> +			u64		 debug_frame_offset;
> >> +			u64		 eh_frame_hdr_offset;
> >> +		} data;
> >> +		/* bpf prog information */
> >> +		struct {
> >> +			u32		id;
> >> +			u32		sub_id;
> >> +			struct perf_env	*env;
> >> +		} bpf_prog;
> >> +	};
> >> 
> >> 	union { /* Tool specific area */
> >> 		void	 *priv;
> >> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> >> index 758bf5f74e6e..4e2e304d4037 100644
> >> --- a/tools/perf/util/symbol.c
> >> +++ b/tools/perf/util/symbol.c
> >> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
> >> 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
> >> 		return true;
> >> 
> >> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> >> 	case DSO_BINARY_TYPE__NOT_FOUND:
> >> 	default:
> >> 		return false;
> >> -- 
> >> 2.17.1
> > 
> > -- 
> > 
> > - Arnaldo

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19  6:10       ` Song Liu
@ 2019-03-19 13:37         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 13:37 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel, ast,
	daniel, Kernel Team, peterz, acme, jolsa, namhyung, sdf

Em Tue, Mar 19, 2019 at 06:10:42AM +0000, Song Liu escreveu:
> 
> 
> > On Mar 18, 2019, at 9:43 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > 
> > Em Mon, Mar 18, 2019 at 01:38:48PM -0300, Arnaldo Carvalho de Melo escreveu:
> >> Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
> >>> This patch enables the annotation of bpf program.
> >>> 
> >>> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
> >>> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
> >>> calls into a new function symbol__disassemble_bpf(), where annotation
> >>> line information is filled based bpf_prog_info and btf saved in given
> >>> perf_env.
> >>> 
> >>> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
> >>> 
> >>> Signed-off-by: Song Liu <songliubraving@fb.com>
> >>> ---
> >>> tools/build/Makefile.feature |   6 +-
> >>> tools/perf/Makefile.config   |   4 +
> >> 
> >> I see the changes to these two files, but I can't see the feature test
> >> that it triggers, forgot to do a git-add? Or is it in an upcoming patch
> >> in this series?
> >> 
> >> After applying this test it "works":
> >> 
> >>  make: Entering directory '/home/acme/git/perf/tools/perf'
> >>    BUILD:   Doing 'make -j8' parallel build
> >> 
> >>  Auto-detecting system features:
> >>  ...                         dwarf: [ on  ]
> >>  ...            dwarf_getlocations: [ on  ]
> >>  <SNIP>
> >>  ...                           bpf: [ on  ]
> >>  ...                        libaio: [ on  ]
> >>  ...        disassembler-four-args: [ on  ]
> >> 
> >> Because you added it to FEATURE_TESTS_BASIC, and this means that if
> >> tools/build/feature/test-all.c builds, then what is in
> >> FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> >> tools/build/feature/test-all.c, so it works because all the other
> >> features are present.
> >> 
> >> Take a look at:
> >> 
> >>  2a07d814747b ("tools build feature: Check if libaio is available")
> >> 
> >> To see what needs to be done.
> >> 
> >> Either way, its interesting to break this patch in two, one adding the
> >> feature test and another to use it, i.e. the second patch out of this
> >> should have the commit log message in this patch.
> >> 
> >> I've applied the patches up to before this one and will continue
> >> processing other patches while you address this.
> > 
> > Ok, to continue processing the other patches I chunked out the part
> > below into a 3rd patch from the above one and have it applied already.
> 
> Could you please push applied patches to the tmp.perf/bpf-annotation 
> branch? 

It is in my perf/core branch already.
 
> Thanks,
> Song
> 
> > 
> > commit f326de312abc3657b0397817c66cd7e1540655f7
> > Author: Song Liu <songliubraving@fb.com>
> > Date:   Mon Mar 11 22:30:48 2019 -0700
> > 
> >    perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO
> > 
> >    Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In
> >    symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new
> >    function symbol__disassemble_bpf() in an upcoming patch, where annotation line
> >    information is filled based bpf_prog_info and btf saved in given perf_env.
> > 
> >    Signed-off-by: Song Liu <songliubraving@fb.com>
> >    Reviewed-by: Jiri Olsa <jolsa@kernel.org>
> >    Cc: Alexei Starovoitov <ast@kernel.org>
> >    Cc: Daniel Borkmann <daniel@iogearbox.net>
> >    Cc: Namhyung Kim <namhyung@kernel.org>
> >    Cc: Peter Zijlstra <peterz@infradead.org>
> >    Cc: Stanislav Fomichev <sdf@google.com>
> >    Cc: kernel-team@fb.com
> >    Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
> >    [ split from a larger patch ]
> >    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > 
> > diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> > index ba58ba603b69..58547c468c65 100644
> > --- a/tools/perf/util/dso.c
> > +++ b/tools/perf/util/dso.c
> > @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
> > 	case DSO_BINARY_TYPE__KALLSYMS:
> > 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
> > 	case DSO_BINARY_TYPE__JAVA_JIT:
> > +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> > 	case DSO_BINARY_TYPE__NOT_FOUND:
> > 		ret = -1;
> > 		break;
> > diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> > index bb417c54c25a..c274b5aa839d 100644
> > --- a/tools/perf/util/dso.h
> > +++ b/tools/perf/util/dso.h
> > @@ -14,6 +14,7 @@
> > 
> > struct machine;
> > struct map;
> > +struct perf_env;
> > 
> > enum dso_binary_type {
> > 	DSO_BINARY_TYPE__KALLSYMS = 0,
> > @@ -35,6 +36,7 @@ enum dso_binary_type {
> > 	DSO_BINARY_TYPE__KCORE,
> > 	DSO_BINARY_TYPE__GUEST_KCORE,
> > 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
> > +	DSO_BINARY_TYPE__BPF_PROG_INFO,
> > 	DSO_BINARY_TYPE__NOT_FOUND,
> > };
> > 
> > @@ -178,17 +180,25 @@ struct dso {
> > 	struct auxtrace_cache *auxtrace_cache;
> > 	int		 comp;
> > 
> > -	/* dso data file */
> > -	struct {
> > -		struct rb_root	 cache;
> > -		int		 fd;
> > -		int		 status;
> > -		u32		 status_seen;
> > -		size_t		 file_size;
> > -		struct list_head open_entry;
> > -		u64		 debug_frame_offset;
> > -		u64		 eh_frame_hdr_offset;
> > -	} data;
> > +	union {
> > +		/* dso data file */
> > +		struct {
> > +			struct rb_root	 cache;
> > +			int		 fd;
> > +			int		 status;
> > +			u32		 status_seen;
> > +			size_t		 file_size;
> > +			struct list_head open_entry;
> > +			u64		 debug_frame_offset;
> > +			u64		 eh_frame_hdr_offset;
> > +		} data;
> > +		/* bpf prog information */
> > +		struct {
> > +			u32		id;
> > +			u32		sub_id;
> > +			struct perf_env	*env;
> > +		} bpf_prog;
> > +	};
> > 
> > 	union { /* Tool specific area */
> > 		void	 *priv;
> > diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> > index 58442ca5e3c4..5cbad55cd99d 100644
> > --- a/tools/perf/util/symbol.c
> > +++ b/tools/perf/util/symbol.c
> > @@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
> > 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
> > 		return true;
> > 
> > +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> > 	case DSO_BINARY_TYPE__NOT_FOUND:
> > 	default:
> > 		return false;

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19  6:05     ` Song Liu
  2019-03-19 13:37       ` Arnaldo Carvalho de Melo
@ 2019-03-19 13:58       ` Arnaldo Carvalho de Melo
  2019-03-19 14:14         ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 13:58 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu:
> Sorry for the late response. 
> 
> > On Mar 18, 2019, at 9:38 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > 
> > Em Mon, Mar 11, 2019 at 10:30:48PM -0700, Song Liu escreveu:
> >> This patch enables the annotation of bpf program.
> >> 
> >> A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
> >> programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
> >> calls into a new function symbol__disassemble_bpf(), where annotation
> >> line information is filled based bpf_prog_info and btf saved in given
> >> perf_env.
> >> 
> >> symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
> >> 
> >> Signed-off-by: Song Liu <songliubraving@fb.com>
> >> ---
> >> tools/build/Makefile.feature |   6 +-
> >> tools/perf/Makefile.config   |   4 +
> > 
> > I see the changes to these two files, but I can't see the feature test
> > that it triggers, forgot to do a git-add? Or is it in an upcoming patch
> > in this series?
> 
> test-disassembler-four-args.c is an existing test used by bpftool.
> It was added in fb982666e380c1632a74495b68b3c33a66e76430 .  
> 
> > 
> > After applying this test it "works":
> > 
> >  make: Entering directory '/home/acme/git/perf/tools/perf'
> >    BUILD:   Doing 'make -j8' parallel build
> > 
> >  Auto-detecting system features:
> >  ...                         dwarf: [ on  ]
> >  ...            dwarf_getlocations: [ on  ]
> >  <SNIP>
> >  ...                           bpf: [ on  ]
> >  ...                        libaio: [ on  ]
> >  ...        disassembler-four-args: [ on  ]
> > 
> > Because you added it to FEATURE_TESTS_BASIC, and this means that if
> > tools/build/feature/test-all.c builds, then what is in
> > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> > tools/build/feature/test-all.c, so it works because all the other
> > features are present.
> > 
> > Take a look at:
> > 
> >  2a07d814747b ("tools build feature: Check if libaio is available")
> > 
> > To see what needs to be done.
> 
> I used different versions of gcc to verify that current version of the 
> patch works for both test-succeed and test-fail cases. I guess something 
> like the following is needed? But the test does work without it. 

Even with the file below, it fails, as:

[acme@quaco perf]$ cat /tmp/build/perf/feature/test-all.make.output
/usr/bin/ld: /tmp/ccTj7iV6.o: in function `main_test_disassembler_four_args':
/home/acme/git/perf/tools/build/feature/test-disassembler-four-args.c:9: undefined reference to `disassembler'
collect2: error: ld returned 1 exit status
[acme@quaco perf]$

Then we do the test for each of the features and _then_ this works:

[acme@quaco perf]$ ls -la /tmp/build/perf/feature/test-disassembler-four-args.*
-rwxrwxr-x. 1 acme acme 2098312 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.bin
-rw-rw-r--. 1 acme acme    1079 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.d
-rw-rw-r--. 1 acme acme       0 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.make.output
[acme@quaco perf]$

So there is still something missing, i.e. which objects to add to the
test-all case, I'll fix it.
 
> Thanks,
> Song
> 
> 
> diff --git i/tools/build/feature/test-all.c w/tools/build/feature/test-all.c
> index e903b86b742f..7853e6d91090 100644
> --- i/tools/build/feature/test-all.c
> +++ w/tools/build/feature/test-all.c
> @@ -178,6 +178,10 @@
>  # include "test-reallocarray.c"
>  #undef main
> 
> +#define main main_test_disassembler_four_args
> +# include "test-disassembler-four-args.c"
> +#undef main
> +
>  int main(int argc, char *argv[])
>  {
>         main_test_libpython();
> @@ -219,6 +223,7 @@ int main(int argc, char *argv[])
>         main_test_setns();
>         main_test_libaio();
>         main_test_reallocarray();
> +       main_test_disassembler_four_args();
> 
>         return 0;
>  }
> 
> 
> > 
> > Either way, its interesting to break this patch in two, one adding the
> > feature test and another to use it, i.e. the second patch out of this
> > should have the commit log message in this patch.
> > 
> > I've applied the patches up to before this one and will continue
> > processing other patches while you address this.
> > 
> > Thanks,
> > 
> > - Arnaldo
> > 
> >> tools/perf/util/annotate.c   | 150 ++++++++++++++++++++++++++++++++++-
> >> tools/perf/util/dso.c        |   1 +
> >> tools/perf/util/dso.h        |  32 +++++---
> >> tools/perf/util/symbol.c     |   1 +
> >> 6 files changed, 180 insertions(+), 14 deletions(-)
> >> 
> >> diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
> >> index 61e46d54a67c..8d3864b061f3 100644
> >> --- a/tools/build/Makefile.feature
> >> +++ b/tools/build/Makefile.feature
> >> @@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
> >>         sched_getcpu			\
> >>         sdt				\
> >>         setns				\
> >> -        libaio
> >> +        libaio				\
> >> +        disassembler-four-args
> >> 
> >> # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
> >> # of all feature tests
> >> @@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
> >>          lzma                   \
> >>          get_cpuid              \
> >>          bpf			\
> >> -         libaio
> >> +         libaio			\
> >> +         disassembler-four-args
> >> 
> >> # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
> >> # If in the future we need per-feature checks/flags for features not
> >> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> >> index df4ad45599ca..c51b59e43dcc 100644
> >> --- a/tools/perf/Makefile.config
> >> +++ b/tools/perf/Makefile.config
> >> @@ -808,6 +808,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
> >>     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
> >> endif
> >> 
> >> +ifeq ($(feature-disassembler-four-args), 1)
> >> +    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
> >> +endif
> >> +
> >> ifeq (${IS_64_BIT}, 1)
> >>   ifndef NO_PERF_READ_VDSO32
> >>     $(call feature_check,compile-32)
> >> diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
> >> index 5f6dbbf5d749..e492b19a157c 100644
> >> --- a/tools/perf/util/annotate.c
> >> +++ b/tools/perf/util/annotate.c
> >> @@ -10,6 +10,10 @@
> >> #include <errno.h>
> >> #include <inttypes.h>
> >> #include <libgen.h>
> >> +#include <bpf/bpf.h>
> >> +#include <bpf/btf.h>
> >> +#include <bpf/libbpf.h>
> >> +#include <linux/btf.h>
> >> #include "util.h"
> >> #include "ui/ui.h"
> >> #include "sort.h"
> >> @@ -24,6 +28,7 @@
> >> #include "annotate.h"
> >> #include "evsel.h"
> >> #include "evlist.h"
> >> +#include "bpf-event.h"
> >> #include "block-range.h"
> >> #include "string2.h"
> >> #include "arch/common.h"
> >> @@ -31,6 +36,9 @@
> >> #include <pthread.h>
> >> #include <linux/bitops.h>
> >> #include <linux/kernel.h>
> >> +#include <bfd.h>
> >> +#include <dis-asm.h>
> >> +#include <bpf/libbpf.h>
> >> 
> >> /* FIXME: For the HE_COLORSET */
> >> #include "ui/browser.h"
> >> @@ -1674,6 +1682,144 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
> >> 	return 0;
> >> }
> >> 
> >> +static int symbol__disassemble_bpf(struct symbol *sym,
> >> +				   struct annotate_args *args)
> >> +{
> >> +	struct annotation *notes = symbol__annotation(sym);
> >> +	struct annotation_options *opts = args->options;
> >> +	struct bpf_prog_info_linear *info_linear;
> >> +	struct bpf_prog_linfo *prog_linfo = NULL;
> >> +	struct bpf_prog_info_node *info_node;
> >> +	int len = sym->end - sym->start;
> >> +	disassembler_ftype disassemble;
> >> +	struct map *map = args->ms.map;
> >> +	struct disassemble_info info;
> >> +	struct dso *dso = map->dso;
> >> +	int pc = 0, count, sub_id;
> >> +	struct btf *btf = NULL;
> >> +	char tpath[PATH_MAX];
> >> +	size_t buf_size;
> >> +	int nr_skip = 0;
> >> +	int ret = -1;
> >> +	char *buf;
> >> +	bfd *bfdf;
> >> +	FILE *s;
> >> +
> >> +	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
> >> +		return -1;
> >> +
> >> +	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
> >> +		 sym->name, sym->start, sym->end - sym->start);
> >> +
> >> +	memset(tpath, 0, sizeof(tpath));
> >> +	perf_exe(tpath, sizeof(tpath));
> >> +
> >> +	bfdf = bfd_openr(tpath, NULL);
> >> +	assert(bfdf);
> >> +	assert(bfd_check_format(bfdf, bfd_object));
> >> +
> >> +	s = open_memstream(&buf, &buf_size);
> >> +	if (!s)
> >> +		goto out;
> >> +	init_disassemble_info(&info, s,
> >> +			      (fprintf_ftype) fprintf);
> >> +
> >> +	info.arch = bfd_get_arch(bfdf);
> >> +	info.mach = bfd_get_mach(bfdf);
> >> +
> >> +	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
> >> +						 dso->bpf_prog.id);
> >> +	if (!info_node)
> >> +		goto out;
> >> +	info_linear = info_node->info_linear;
> >> +	sub_id = dso->bpf_prog.sub_id;
> >> +
> >> +	info.buffer = (void *)(info_linear->info.jited_prog_insns);
> >> +	info.buffer_length = info_linear->info.jited_prog_len;
> >> +
> >> +	if (info_linear->info.nr_line_info)
> >> +		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
> >> +
> >> +	if (info_linear->info.btf_id) {
> >> +		struct btf_node *node;
> >> +
> >> +		node = perf_env__find_btf(dso->bpf_prog.env,
> >> +					  info_linear->info.btf_id);
> >> +		if (node)
> >> +			btf = btf__new((__u8 *)(node->data),
> >> +				       node->data_size);
> >> +	}
> >> +
> >> +	disassemble_init_for_target(&info);
> >> +
> >> +#ifdef DISASM_FOUR_ARGS_SIGNATURE
> >> +	disassemble = disassembler(info.arch,
> >> +				   bfd_big_endian(bfdf),
> >> +				   info.mach,
> >> +				   bfdf);
> >> +#else
> >> +	disassemble = disassembler(bfdf);
> >> +#endif
> >> +	assert(disassemble);
> >> +
> >> +	fflush(s);
> >> +	do {
> >> +		const struct bpf_line_info *linfo = NULL;
> >> +		struct disasm_line *dl;
> >> +		size_t prev_buf_size;
> >> +		const char *srcline;
> >> +		u64 addr;
> >> +
> >> +		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
> >> +		count = disassemble(pc, &info);
> >> +
> >> +		if (prog_linfo)
> >> +			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
> >> +								addr, sub_id,
> >> +								nr_skip);
> >> +
> >> +		if (linfo && btf) {
> >> +			srcline = btf__name_by_offset(btf, linfo->line_off);
> >> +			nr_skip++;
> >> +		} else
> >> +			srcline = NULL;
> >> +
> >> +		fprintf(s, "\n");
> >> +		prev_buf_size = buf_size;
> >> +		fflush(s);
> >> +
> >> +		if (!opts->hide_src_code && srcline) {
> >> +			args->offset = -1;
> >> +			args->line = strdup(srcline);
> >> +			args->line_nr = 0;
> >> +			args->ms.sym  = sym;
> >> +			dl = disasm_line__new(args);
> >> +			if (dl) {
> >> +				annotation_line__add(&dl->al,
> >> +						     &notes->src->source);
> >> +			}
> >> +		}
> >> +
> >> +		args->offset = pc;
> >> +		args->line = buf + prev_buf_size;
> >> +		args->line_nr = 0;
> >> +		args->ms.sym  = sym;
> >> +		dl = disasm_line__new(args);
> >> +		if (dl)
> >> +			annotation_line__add(&dl->al, &notes->src->source);
> >> +
> >> +		pc += count;
> >> +	} while (count > 0 && pc < len);
> >> +
> >> +	ret = 0;
> >> +out:
> >> +	free(prog_linfo);
> >> +	free(btf);
> >> +	fclose(s);
> >> +	bfd_close(bfdf);
> >> +	return ret;
> >> +}
> >> +
> >> static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
> >> {
> >> 	struct annotation_options *opts = args->options;
> >> @@ -1701,7 +1847,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
> >> 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
> >> 		 dso, dso->long_name, sym, sym->name);
> >> 
> >> -	if (dso__is_kcore(dso)) {
> >> +	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
> >> +		return symbol__disassemble_bpf(sym, args);
> >> +	} else if (dso__is_kcore(dso)) {
> >> 		kce.kcore_filename = symfs_filename;
> >> 		kce.addr = map__rip_2objdump(map, sym->start);
> >> 		kce.offs = sym->start;
> >> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> >> index ba58ba603b69..58547c468c65 100644
> >> --- a/tools/perf/util/dso.c
> >> +++ b/tools/perf/util/dso.c
> >> @@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
> >> 	case DSO_BINARY_TYPE__KALLSYMS:
> >> 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
> >> 	case DSO_BINARY_TYPE__JAVA_JIT:
> >> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> >> 	case DSO_BINARY_TYPE__NOT_FOUND:
> >> 		ret = -1;
> >> 		break;
> >> diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
> >> index bb417c54c25a..c274b5aa839d 100644
> >> --- a/tools/perf/util/dso.h
> >> +++ b/tools/perf/util/dso.h
> >> @@ -14,6 +14,7 @@
> >> 
> >> struct machine;
> >> struct map;
> >> +struct perf_env;
> >> 
> >> enum dso_binary_type {
> >> 	DSO_BINARY_TYPE__KALLSYMS = 0,
> >> @@ -35,6 +36,7 @@ enum dso_binary_type {
> >> 	DSO_BINARY_TYPE__KCORE,
> >> 	DSO_BINARY_TYPE__GUEST_KCORE,
> >> 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
> >> +	DSO_BINARY_TYPE__BPF_PROG_INFO,
> >> 	DSO_BINARY_TYPE__NOT_FOUND,
> >> };
> >> 
> >> @@ -178,17 +180,25 @@ struct dso {
> >> 	struct auxtrace_cache *auxtrace_cache;
> >> 	int		 comp;
> >> 
> >> -	/* dso data file */
> >> -	struct {
> >> -		struct rb_root	 cache;
> >> -		int		 fd;
> >> -		int		 status;
> >> -		u32		 status_seen;
> >> -		size_t		 file_size;
> >> -		struct list_head open_entry;
> >> -		u64		 debug_frame_offset;
> >> -		u64		 eh_frame_hdr_offset;
> >> -	} data;
> >> +	union {
> >> +		/* dso data file */
> >> +		struct {
> >> +			struct rb_root	 cache;
> >> +			int		 fd;
> >> +			int		 status;
> >> +			u32		 status_seen;
> >> +			size_t		 file_size;
> >> +			struct list_head open_entry;
> >> +			u64		 debug_frame_offset;
> >> +			u64		 eh_frame_hdr_offset;
> >> +		} data;
> >> +		/* bpf prog information */
> >> +		struct {
> >> +			u32		id;
> >> +			u32		sub_id;
> >> +			struct perf_env	*env;
> >> +		} bpf_prog;
> >> +	};
> >> 
> >> 	union { /* Tool specific area */
> >> 		void	 *priv;
> >> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> >> index 758bf5f74e6e..4e2e304d4037 100644
> >> --- a/tools/perf/util/symbol.c
> >> +++ b/tools/perf/util/symbol.c
> >> @@ -1451,6 +1451,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
> >> 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
> >> 		return true;
> >> 
> >> +	case DSO_BINARY_TYPE__BPF_PROG_INFO:
> >> 	case DSO_BINARY_TYPE__NOT_FOUND:
> >> 	default:
> >> 		return false;
> >> -- 
> >> 2.17.1
> > 
> > -- 
> > 
> > - Arnaldo

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19 13:58       ` Arnaldo Carvalho de Melo
@ 2019-03-19 14:14         ` Arnaldo Carvalho de Melo
  2019-03-19 14:52           ` [WORKS!] " Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 14:14 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 10:58:13AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Mar 19, 2019 at 06:05:30AM +0000, Song Liu escreveu:
> > test-disassembler-four-args.c is an existing test used by bpftool.
> > It was added in fb982666e380c1632a74495b68b3c33a66e76430 .  

> > > After applying this test it "works":

> > >  make: Entering directory '/home/acme/git/perf/tools/perf'
> > >    BUILD:   Doing 'make -j8' parallel build

> > >  Auto-detecting system features:
> > >  ...                         dwarf: [ on  ]
> > >  ...            dwarf_getlocations: [ on  ]
> > >  <SNIP>
> > >  ...                           bpf: [ on  ]
> > >  ...                        libaio: [ on  ]
> > >  ...        disassembler-four-args: [ on  ]
> > > 
> > > Because you added it to FEATURE_TESTS_BASIC, and this means that if
> > > tools/build/feature/test-all.c builds, then what is in
> > > FEATURE_TESTS_BASIC is set to 'on', but you didn't add anything to
> > > tools/build/feature/test-all.c, so it works because all the other
> > > features are present.

> > > Take a look at:

> > >  2a07d814747b ("tools build feature: Check if libaio is available")

> > > To see what needs to be done.

> > I used different versions of gcc to verify that current version of the 
> > patch works for both test-succeed and test-fail cases. I guess something 
> > like the following is needed? But the test does work without it. 

> Even with the file below, it fails, as:

> [acme@quaco perf]$ cat /tmp/build/perf/feature/test-all.make.output
> /usr/bin/ld: /tmp/ccTj7iV6.o: in function `main_test_disassembler_four_args':
> /home/acme/git/perf/tools/build/feature/test-disassembler-four-args.c:9: undefined reference to `disassembler'
> collect2: error: ld returned 1 exit status
> [acme@quaco perf]$

> Then we do the test for each of the features and _then_ this works:

> [acme@quaco perf]$ ls -la /tmp/build/perf/feature/test-disassembler-four-args.*
> -rwxrwxr-x. 1 acme acme 2098312 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.bin
> -rw-rw-r--. 1 acme acme    1079 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.d
> -rw-rw-r--. 1 acme acme       0 Mar 19 10:51 /tmp/build/perf/feature/test-disassembler-four-args.make.output
> [acme@quaco perf]$
> 
> So there is still something missing, i.e. which objects to add to the
> test-all case, I'll fix it.

This was missing:

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index c51b59e43dcc..4f491ad4f492 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -227,6 +227,8 @@ FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
 
 FEATURE_CHECK_LDFLAGS-libaio = -lrt
 
+FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lopcodes
+
 CFLAGS += -fno-omit-frame-pointer
 CFLAGS += -ggdb3
 CFLAGS += -funwind-tables

----------------------

After that, and with a clean /tmp/build/perf, re-running:

  make -C tools/perf O=/tmp/build/perf

we get:

[acme@quaco perf]$ ls -la /tmp/build/perf/feature/
total 2888
drwxrwxr-x.  2 acme acme     400 Mar 19 11:08 .
drwxrwxr-x. 16 acme acme    4280 Mar 19 11:08 ..
-rwxrwxr-x.  1 acme acme 2680352 Mar 19 11:07 test-all.bin
-rw-rw-r--.  1 acme acme   38753 Mar 19 11:07 test-all.d
-rw-rw-r--.  1 acme acme       0 Mar 19 11:07 test-all.make.output
-rw-rw-r--.  1 acme acme     168 Mar 19 11:07 test-bionic.make.output
-rwxrwxr-x.  1 acme acme  140960 Mar 19 11:08 test-cplus-demangle.bin
-rw-rw-r--.  1 acme acme     101 Mar 19 11:08 test-cplus-demangle.d
-rw-rw-r--.  1 acme acme       0 Mar 19 11:08 test-cplus-demangle.make.output
-rwxrwxr-x.  1 acme acme   17976 Mar 19 11:08 test-jvmti.bin
-rwxrwxr-x.  1 acme acme   17984 Mar 19 11:08 test-jvmti-cmlr.bin
-rw-rw-r--.  1 acme acme    1107 Mar 19 11:08 test-jvmti-cmlr.d
-rw-rw-r--.  1 acme acme       0 Mar 19 11:08 test-jvmti-cmlr.make.output
-rw-rw-r--.  1 acme acme    1014 Mar 19 11:08 test-jvmti.d
-rw-rw-r--.  1 acme acme       0 Mar 19 11:08 test-jvmti.make.output
-rwxrwxr-x.  1 acme acme   18368 Mar 19 11:07 test-libbabeltrace.bin
-rw-rw-r--.  1 acme acme    1470 Mar 19 11:07 test-libbabeltrace.d
-rw-rw-r--.  1 acme acme       0 Mar 19 11:07 test-libbabeltrace.make.output
-rw-rw-r--.  1 acme acme     179 Mar 19 11:07 test-libunwind-aarch64.make.output
-rw-rw-r--.  1 acme acme     163 Mar 19 11:07 test-libunwind-x86.make.output
[acme@quaco perf]$

I.e. test-all.bin got built, and if we look at it:

[acme@quaco perf]$ nm /tmp/build/perf/feature/test-all.bin  | grep disassembler
0000000000061f90 T disassembler
0000000000062110 T disassembler_options_cmp
0000000000061fb0 T disassembler_usage
0000000000061f40 T main_test_disassembler_four_args
000000000006b7c0 T print_i386_disassembler_options
[acme@quaco perf]$ 

I.e. the -lopcodes was added to the test-all.bin, and as we include that
itest-disassembler-four-args.c in the test-all.c file, it gets linked
and that test-all.c build doesn't fail, so all that is in
FEATURE_TESTS_BASIC is marked as present, CFLAGS +=
-DDISASM_FOUR_ARGS_SIGNATURE gets set, etc.

Now the test is really being performed, the test-all.bin feature
detection fast path is working, proceeding.

- Arnaldo

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [WORKS!] Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19 14:14         ` Arnaldo Carvalho de Melo
@ 2019-03-19 14:52           ` Arnaldo Carvalho de Melo
  2019-03-19 16:51             ` Song Liu
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 14:52 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu:
> 
> Now the test is really being performed, the test-all.bin feature
> detection fast path is working, proceeding.

Now it all works, really nice!

I added a 'Committer testing' section with all the steps to test this
and pushed to:

https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f

Which I repeat here, please go thru it and check if everything is ok, if
the disassembled + original BPF source code looks ok, etc:

    Committer testing:
    
    1) Have a BPF program running, one that has BTF info, etc, I used
       the tools/perf/examples/bpf/augmented_raw_syscalls.c put in place
       by 'perf trace'.
    
      # grep -B1 augmented_raw ~/.perfconfig
      [trace]
            add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c
      #
      # perf trace -e *mmsg
      dnf/6245 sendmmsg(20, 0x7f5485a88030, 2, MSG_NOSIGNAL) = 2
      NetworkManager/10055 sendmmsg(22<socket:[1056822]>, 0x7f8126ad1bb0, 2, MSG_NOSIGNAL) = 2
    
    2) Then do a 'perf record' system wide for a while:
    
      # perf record -a
      ^C[ perf record: Woken up 68 times to write data ]
      [ perf record: Captured and wrote 19.427 MB perf.data (366891 samples) ]
      #
    
    3) Check that we captured BPF and BTF info in the perf.data file:
    
      # perf report --header-only | grep 'b[pt]f'
      # event : name = cycles:ppp, , id = { 294789, 294790, 294791, 294792, 294793, 294794, 294795, 294796 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1
      # bpf_prog_info of id 13
      # bpf_prog_info of id 14
      # bpf_prog_info of id 15
      # bpf_prog_info of id 16
      # bpf_prog_info of id 17
      # bpf_prog_info of id 18
      # bpf_prog_info of id 21
      # bpf_prog_info of id 22
      # bpf_prog_info of id 41
      # bpf_prog_info of id 42
      # btf info of id 2
      #
    
    4) Check which programs got recorded:
    
       # perf report | grep bpf_prog | head
         0.16%  exe              bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
         0.14%  exe              bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
         0.08%  fuse-overlayfs   bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
         0.07%  fuse-overlayfs   bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
         0.01%  clang-4.0        bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
         0.01%  clang-4.0        bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
         0.00%  clang            bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
         0.00%  runc             bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
         0.00%  clang            bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
         0.00%  sh               bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
      #
    
      This was with the default --sort order for 'perf report', which is:
    
        --sort comm,dso,symbol
    
      If we just look for the symbol, for instance:
    
       # perf report --sort symbol | grep bpf_prog | head
         0.26%  [k] bpf_prog_819967866022f1e1_sys_enter                -      -
         0.24%  [k] bpf_prog_c1bd85c092d6e4aa_sys_exit                 -      -
       #
    
      or the DSO:
    
       # perf report --sort dso | grep bpf_prog | head
         0.26%  bpf_prog_819967866022f1e1_sys_enter
         0.24%  bpf_prog_c1bd85c092d6e4aa_sys_exit
      #
    
    We'll see the two BPF programs that augmented_raw_syscalls.o puts in
    place,  one attached to the raw_syscalls:sys_enter and another to the
    raw_syscalls:sys_exit tracepoints, as expected.
    
    Now we can finally do, from the command line, annotation for one of
    those two symbols, with the original BPF program source coude intermixed
    with the disassembled JITed code:
    
      # perf annotate --stdio2 bpf_prog_819967866022f1e1_sys_enter
    
      Samples: 950  of event 'cycles:ppp', 4000 Hz, Event count (approx.): 553756947, [percent: local period]
      bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
      Percent      int sys_enter(struct syscall_enter_args *args)
       53.41         push   %rbp
    
        0.63         mov    %rsp,%rbp
        0.31         sub    $0x170,%rsp
        1.93         sub    $0x28,%rbp
        7.02         mov    %rbx,0x0(%rbp)
        3.20         mov    %r13,0x8(%rbp)
        1.07         mov    %r14,0x10(%rbp)
        0.61         mov    %r15,0x18(%rbp)
        0.11         xor    %eax,%eax
        1.29         mov    %rax,0x20(%rbp)
        0.11         mov    %rdi,%rbx
                    return bpf_get_current_pid_tgid();
        2.02       → callq  *ffffffffda6776d9
        2.76         mov    %eax,-0x148(%rbp)
                     mov    %rbp,%rsi
                   int sys_enter(struct syscall_enter_args *args)
                     add    $0xfffffffffffffeb8,%rsi
                    return bpf_map_lookup_elem(pids, &pid) != NULL;
                     movabs $0xffff975ac2607800,%rdi
    
        1.26       → callq  *ffffffffda6789e9
                     cmp    $0x0,%rax
        2.43       → je     0
                     add    $0x38,%rax
        0.21         xor    %r13d,%r13d
                    if (pid_filter__has(&pids_filtered, getpid()))
        0.81         cmp    $0x0,%rax
                   → jne    0
                     mov    %rbp,%rdi
                    probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
        2.22         add    $0xfffffffffffffeb8,%rdi
        0.11         mov    $0x40,%esi
        0.32         mov    %rbx,%rdx
        2.74       → callq  *ffffffffda658409
                    syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
        0.22         mov    %rbp,%rsi
        1.69         add    $0xfffffffffffffec0,%rsi
                    syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
                     movabs $0xffff975bfcd36000,%rdi
    
                     add    $0xd0,%rdi
        0.21         mov    0x0(%rsi),%eax
        0.93         cmp    $0x200,%rax
                   → jae    0
        0.10         shl    $0x3,%rax
    
        0.11         add    %rdi,%rax
        0.11       → jmp    0
                     xor    %eax,%eax
                    if (syscall == NULL || !syscall->enabled)
        1.07         cmp    $0x0,%rax
                   → je     0
                    if (syscall == NULL || !syscall->enabled)
        6.57         movzbq 0x0(%rax),%rdi
    
                    if (syscall == NULL || !syscall->enabled)
                     cmp    $0x0,%rdi
        0.95       → je     0
                     mov    $0x40,%r8d
                    switch (augmented_args.args.syscall_nr) {
                     mov    -0x140(%rbp),%rdi
                    switch (augmented_args.args.syscall_nr) {
                     cmp    $0x2,%rdi
                   → je     0
                     cmp    $0x101,%rdi
                   → je     0
                     cmp    $0x15,%rdi
                   → jne    0
                    case SYS_OPEN:   filename_arg = (const void *)args->args[0];
                     mov    0x10(%rbx),%rdx
                   → jmp    0
                    case SYS_OPENAT: filename_arg = (const void *)args->args[1];
                     mov    0x18(%rbx),%rdx
                    if (filename_arg != NULL) {
                     cmp    $0x0,%rdx
                   → je     0
                     xor    %edi,%edi
                            augmented_args.filename.reserved = 0;
                     mov    %edi,-0x104(%rbp)
                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                     mov    %rbp,%rdi
                     add    $0xffffffffffffff00,%rdi
                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                     mov    $0x100,%esi
                   → callq  *ffffffffda658499
                     mov    $0x148,%r8d
                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                     mov    %eax,-0x108(%rbp)
                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                     mov    %rax,%rdi
                     shl    $0x20,%rdi
    
                     shr    $0x20,%rdi
    
                            if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
                     cmp    $0xff,%rdi
                   → ja     0
                                    len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
                     add    $0x48,%rax
                                    len &= sizeof(augmented_args.filename.value) - 1;
                     and    $0xff,%rax
                     mov    %rax,%r8
                     mov    %rbp,%rcx
                    return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
                     add    $0xfffffffffffffeb8,%rcx
                     mov    %rbx,%rdi
                     movabs $0xffff975fbd72d800,%rsi
    
                     mov    $0xffffffff,%edx
                   → callq  *ffffffffda658ad9
                     mov    %rax,%r13
                   }
                     mov    %r13,%rax
        0.72         mov    0x0(%rbp),%rbx
                     mov    0x8(%rbp),%r13
        1.16         mov    0x10(%rbp),%r14
        0.10         mov    0x18(%rbp),%r15
        0.42         add    $0x28,%rbp
        0.54         leaveq
        0.54       ← retq
      #
    
    Please see 'man perf-config' to see how to control what should be seen,
    via ~/.perfconfig [annotate] section, for instance, one can suppress the
    source code and see just the disassembly, etc.
    
    Alternatively, use the TUI bu just using 'perf annotate', press
    '/bpf_prog' to see the bpf symbols, press enter and do the interactive
    annotation, which allows for dumping to a file after selecting the
    the various output tunables, for instance, the above without source code
    intermixed, plus showing all the instruction offsets:
    
      # perf annotate bpf_prog_819967866022f1e1_sys_enter
    
    Then press: 's' to hide the source code + 'O' twice to show all
    instruction offsets, then 'P' to print to the
    bpf_prog_819967866022f1e1_sys_enter.annotation file, which will have:
    
      # cat bpf_prog_819967866022f1e1_sys_enter.annotation
      bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
      Event: cycles:ppp
    
       53.41    0:   push   %rbp
    
        0.63    1:   mov    %rsp,%rbp
        0.31    4:   sub    $0x170,%rsp
        1.93    b:   sub    $0x28,%rbp
        7.02    f:   mov    %rbx,0x0(%rbp)
        3.20   13:   mov    %r13,0x8(%rbp)
        1.07   17:   mov    %r14,0x10(%rbp)
        0.61   1b:   mov    %r15,0x18(%rbp)
        0.11   1f:   xor    %eax,%eax
        1.29   21:   mov    %rax,0x20(%rbp)
        0.11   25:   mov    %rdi,%rbx
        2.02   28: → callq  *ffffffffda6776d9
        2.76   2d:   mov    %eax,-0x148(%rbp)
               33:   mov    %rbp,%rsi
               36:   add    $0xfffffffffffffeb8,%rsi
               3d:   movabs $0xffff975ac2607800,%rdi
    
        1.26   47: → callq  *ffffffffda6789e9
               4c:   cmp    $0x0,%rax
        2.43   50: → je     0
               52:   add    $0x38,%rax
        0.21   56:   xor    %r13d,%r13d
        0.81   59:   cmp    $0x0,%rax
               5d: → jne    0
               63:   mov    %rbp,%rdi
        2.22   66:   add    $0xfffffffffffffeb8,%rdi
        0.11   6d:   mov    $0x40,%esi
        0.32   72:   mov    %rbx,%rdx
        2.74   75: → callq  *ffffffffda658409
        0.22   7a:   mov    %rbp,%rsi
        1.69   7d:   add    $0xfffffffffffffec0,%rsi
               84:   movabs $0xffff975bfcd36000,%rdi
    
               8e:   add    $0xd0,%rdi
        0.21   95:   mov    0x0(%rsi),%eax
        0.93   98:   cmp    $0x200,%rax
               9f: → jae    0
        0.10   a1:   shl    $0x3,%rax
    
        0.11   a5:   add    %rdi,%rax
        0.11   a8: → jmp    0
               aa:   xor    %eax,%eax
        1.07   ac:   cmp    $0x0,%rax
               b0: → je     0
        6.57   b6:   movzbq 0x0(%rax),%rdi
    
               bb:   cmp    $0x0,%rdi
        0.95   bf: → je     0
               c5:   mov    $0x40,%r8d
               cb:   mov    -0x140(%rbp),%rdi
               d2:   cmp    $0x2,%rdi
               d6: → je     0
               d8:   cmp    $0x101,%rdi
               df: → je     0
               e1:   cmp    $0x15,%rdi
               e5: → jne    0
               e7:   mov    0x10(%rbx),%rdx
               eb: → jmp    0
               ed:   mov    0x18(%rbx),%rdx
               f1:   cmp    $0x0,%rdx
               f5: → je     0
               f7:   xor    %edi,%edi
               f9:   mov    %edi,-0x104(%rbp)
               ff:   mov    %rbp,%rdi
              102:   add    $0xffffffffffffff00,%rdi
              109:   mov    $0x100,%esi
              10e: → callq  *ffffffffda658499
              113:   mov    $0x148,%r8d
              119:   mov    %eax,-0x108(%rbp)
              11f:   mov    %rax,%rdi
              122:   shl    $0x20,%rdi
    
              126:   shr    $0x20,%rdi
    
              12a:   cmp    $0xff,%rdi
              131: → ja     0
              133:   add    $0x48,%rax
              137:   and    $0xff,%rax
              13d:   mov    %rax,%r8
              140:   mov    %rbp,%rcx
              143:   add    $0xfffffffffffffeb8,%rcx
              14a:   mov    %rbx,%rdi
              14d:   movabs $0xffff975fbd72d800,%rsi
    
              157:   mov    $0xffffffff,%edx
              15c: → callq  *ffffffffda658ad9
              161:   mov    %rax,%r13
              164:   mov    %r13,%rax
        0.72  167:   mov    0x0(%rbp),%rbx
              16b:   mov    0x8(%rbp),%r13
        1.16  16f:   mov    0x10(%rbp),%r14
        0.10  173:   mov    0x18(%rbp),%r15
        0.42  177:   add    $0x28,%rbp
        0.54  17b:   leaveq
        0.54  17c: ← retq
    
    Another cool way to test all this is to symple use 'perf top' look for
    those symbols, go there and press enter, annotate it live :-)
    
    Signed-off-by: Song Liu <songliubraving@fb.com>
    Reviewed-by: Jiri Olsa <jolsa@kernel.org>
    Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: Alexei Starovoitov <ast@kernel.org>
    Cc: Daniel Borkmann <daniel@iogearbox.net>
    Cc: Namhyung Kim <namhyung@kernel.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Stanislav Fomichev <sdf@google.com>
    Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
@ 2019-03-19 15:25   ` Arnaldo Carvalho de Melo
  2019-03-22 22:45   ` [tip:perf/urgent] perf tools: Save bpf_prog_info and BTF of new BPF programs tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 15:25 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

Em Mon, Mar 11, 2019 at 10:30:51PM -0700, Song Liu escreveu:
> To fully annotate BPF programs with source code mapping, 4 different
> information are needed:
>     1) PERF_RECORD_KSYMBOL
>     2) PERF_RECORD_BPF_EVENT
>     3) bpf_prog_info
>     4) btf

The API for the sideband event, etc, needs reworking, I found it
convoluted, but testing shows that it works, so I left improving that
aspect for later.

Also this is not "for short living bpf programs", it is for any program
that starts after you started 'perf record' or 'perf top', so I've
changed in the cset comment log as well.

Now going thru the container build tests prior for upstreaming.

- Arnaldo
 
> This patch handles 3) and 4) for short living BPF programs. For timely
> process of these information, a dedicated event is added to the side
> band evlist. When PERF_RECORD_BPF_EVENT is received via the side band
> event, the polling thread gathers 3) and 4) vis sys_bpf and store them
> in perf_env. These information are saved to perf.data at the end of
> perf-record.
> 
> Signed-off-by: Song Liu <songliubraving@fb.com>
> ---
>  tools/perf/builtin-record.c |  2 +
>  tools/perf/builtin-top.c    |  2 +
>  tools/perf/util/bpf-event.c | 95 +++++++++++++++++++++++++++++++++++++
>  tools/perf/util/bpf-event.h | 15 ++++++
>  4 files changed, 114 insertions(+)
> 
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index f792dd28d936..3c0596a68992 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -1217,6 +1217,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
>  		goto out_child;
>  	}
>  
> +	if (!opts->no_bpf_event)
> +		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
>  	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
>  
>  	err = record__synthesize(rec, false);
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 9577dba4996b..b7790d66cac2 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -1641,6 +1641,8 @@ int cmd_top(int argc, const char **argv)
>  		signal(SIGWINCH, winch_sig);
>  	}
>  
> +	if (!top.record_opts.no_bpf_event)
> +		bpf_event__add_sb_event(&sb_evlist, &perf_env);
>  	perf_evlist__start_sb_thread(sb_evlist, target);
>  
>  	status = __cmd_top(&top);
> diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
> index af434de3a23e..77e0fdead6f4 100644
> --- a/tools/perf/util/bpf-event.c
> +++ b/tools/perf/util/bpf-event.c
> @@ -13,6 +13,7 @@
>  #include "env.h"
>  #include "session.h"
>  #include "map.h"
> +#include "evlist.h"
>  
>  #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
>  
> @@ -330,3 +331,97 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
>  	free(event);
>  	return err;
>  }
> +
> +static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
> +{
> +	struct bpf_prog_info_linear *info_linear;
> +	struct bpf_prog_info_node *info_node;
> +	struct btf *btf = NULL;
> +	u64 arrays;
> +	u32 btf_id;
> +	int fd;
> +
> +	fd = bpf_prog_get_fd_by_id(id);
> +	if (fd < 0)
> +		return;
> +
> +	arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
> +	arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
> +	arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
> +	arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
> +	arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
> +	arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
> +	arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
> +
> +	info_linear = bpf_program__get_prog_info_linear(fd, arrays);
> +	if (IS_ERR_OR_NULL(info_linear)) {
> +		pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
> +		goto out;
> +	}
> +
> +	btf_id = info_linear->info.btf_id;
> +
> +	info_node = malloc(sizeof(struct bpf_prog_info_node));
> +	if (info_node) {
> +		info_node->info_linear = info_linear;
> +		perf_env__insert_bpf_prog_info(env, info_node);
> +	} else
> +		free(info_linear);
> +
> +	if (btf_id == 0)
> +		goto out;
> +
> +	if (btf__get_from_id(btf_id, &btf)) {
> +		pr_debug("%s: failed to get BTF of id %u, aborting\n",
> +			 __func__, btf_id);
> +		goto out;
> +	}
> +	perf_env__fetch_btf(env, btf_id, btf);
> +
> +out:
> +	free(btf);
> +	close(fd);
> +}
> +
> +static int bpf_event__sb_cb(union perf_event *event, void *data)
> +{
> +	struct perf_env *env = data;
> +
> +	if (event->header.type != PERF_RECORD_BPF_EVENT)
> +		return -1;
> +
> +	switch (event->bpf_event.type) {
> +	case PERF_BPF_EVENT_PROG_LOAD:
> +		perf_env__add_bpf_info(env, event->bpf_event.id);
> +
> +	case PERF_BPF_EVENT_PROG_UNLOAD:
> +		/*
> +		 * Do not free bpf_prog_info and btf of the program here,
> +		 * as annotation still need them. They will be freed at
> +		 * the end of the session.
> +		 */
> +		break;
> +	default:
> +		pr_debug("unexpected bpf_event type of %d\n",
> +			 event->bpf_event.type);
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +int bpf_event__add_sb_event(struct perf_evlist **evlist,
> +			    struct perf_env *env)
> +{
> +	struct perf_event_attr attr = {
> +		.type	          = PERF_TYPE_SOFTWARE,
> +		.config           = PERF_COUNT_SW_DUMMY,
> +		.sample_id_all    = 1,
> +		.watermark        = 1,
> +		.bpf_event        = 1,
> +		.wakeup_watermark = 1,
> +		.size	   = sizeof(attr), /* to capture ABI version */
> +	};
> +
> +	return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
> +}
> diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
> index b9ec394dc7c7..249909c826e7 100644
> --- a/tools/perf/util/bpf-event.h
> +++ b/tools/perf/util/bpf-event.h
> @@ -4,12 +4,17 @@
>  
>  #include <linux/compiler.h>
>  #include <linux/rbtree.h>
> +#include <pthread.h>
> +#include <api/fd/array.h>
>  #include "event.h"
>  
>  struct machine;
>  union perf_event;
> +struct perf_env;
>  struct perf_sample;
>  struct record_opts;
> +struct evlist;
> +struct target;
>  
>  struct bpf_prog_info_node {
>  	struct bpf_prog_info_linear	*info_linear;
> @@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
>  				      perf_event__handler_t process,
>  				      struct machine *machine,
>  				      struct record_opts *opts);
> +int bpf_event__add_sb_event(struct perf_evlist **evlist,
> +				 struct perf_env *env);
> +
>  #else
>  static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
>  					     union perf_event *event __maybe_unused,
> @@ -46,5 +54,12 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
>  {
>  	return 0;
>  }
> +
> +static int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
> +				   struct perf_env *env __maybe_unused)
> +{
> +	return 0;
> +}
> +
>  #endif // HAVE_LIBBPF_SUPPORT
>  #endif
> -- 
> 2.17.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [WORKS!] Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19 14:52           ` [WORKS!] " Arnaldo Carvalho de Melo
@ 2019-03-19 16:51             ` Song Liu
  2019-03-19 16:55               ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Song Liu @ 2019-03-19 16:51 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev



> On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> 
> Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu:
>> 
>> Now the test is really being performed, the test-all.bin feature
>> detection fast path is working, proceeding.
> 
> Now it all works, really nice!
> 
> I added a 'Committer testing' section with all the steps to test this
> and pushed to:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f

Thanks Arnaldo! This looks great!

I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch
and resend. 

Song


> Which I repeat here, please go thru it and check if everything is ok, if
> the disassembled + original BPF source code looks ok, etc:
> 
>    Committer testing:
> 
>    1) Have a BPF program running, one that has BTF info, etc, I used
>       the tools/perf/examples/bpf/augmented_raw_syscalls.c put in place
>       by 'perf trace'.
> 
>      # grep -B1 augmented_raw ~/.perfconfig
>      [trace]
>            add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c
>      #
>      # perf trace -e *mmsg
>      dnf/6245 sendmmsg(20, 0x7f5485a88030, 2, MSG_NOSIGNAL) = 2
>      NetworkManager/10055 sendmmsg(22<socket:[1056822]>, 0x7f8126ad1bb0, 2, MSG_NOSIGNAL) = 2
> 
>    2) Then do a 'perf record' system wide for a while:
> 
>      # perf record -a
>      ^C[ perf record: Woken up 68 times to write data ]
>      [ perf record: Captured and wrote 19.427 MB perf.data (366891 samples) ]
>      #
> 
>    3) Check that we captured BPF and BTF info in the perf.data file:
> 
>      # perf report --header-only | grep 'b[pt]f'
>      # event : name = cycles:ppp, , id = { 294789, 294790, 294791, 294792, 294793, 294794, 294795, 294796 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1
>      # bpf_prog_info of id 13
>      # bpf_prog_info of id 14
>      # bpf_prog_info of id 15
>      # bpf_prog_info of id 16
>      # bpf_prog_info of id 17
>      # bpf_prog_info of id 18
>      # bpf_prog_info of id 21
>      # bpf_prog_info of id 22
>      # bpf_prog_info of id 41
>      # bpf_prog_info of id 42
>      # btf info of id 2
>      #
> 
>    4) Check which programs got recorded:
> 
>       # perf report | grep bpf_prog | head
>         0.16%  exe              bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
>         0.14%  exe              bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
>         0.08%  fuse-overlayfs   bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
>         0.07%  fuse-overlayfs   bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
>         0.01%  clang-4.0        bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
>         0.01%  clang-4.0        bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
>         0.00%  clang            bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
>         0.00%  runc             bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
>         0.00%  clang            bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
>         0.00%  sh               bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
>      #
> 
>      This was with the default --sort order for 'perf report', which is:
> 
>        --sort comm,dso,symbol
> 
>      If we just look for the symbol, for instance:
> 
>       # perf report --sort symbol | grep bpf_prog | head
>         0.26%  [k] bpf_prog_819967866022f1e1_sys_enter                -      -
>         0.24%  [k] bpf_prog_c1bd85c092d6e4aa_sys_exit                 -      -
>       #
> 
>      or the DSO:
> 
>       # perf report --sort dso | grep bpf_prog | head
>         0.26%  bpf_prog_819967866022f1e1_sys_enter
>         0.24%  bpf_prog_c1bd85c092d6e4aa_sys_exit
>      #
> 
>    We'll see the two BPF programs that augmented_raw_syscalls.o puts in
>    place,  one attached to the raw_syscalls:sys_enter and another to the
>    raw_syscalls:sys_exit tracepoints, as expected.
> 
>    Now we can finally do, from the command line, annotation for one of
>    those two symbols, with the original BPF program source coude intermixed
>    with the disassembled JITed code:
> 
>      # perf annotate --stdio2 bpf_prog_819967866022f1e1_sys_enter
> 
>      Samples: 950  of event 'cycles:ppp', 4000 Hz, Event count (approx.): 553756947, [percent: local period]
>      bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
>      Percent      int sys_enter(struct syscall_enter_args *args)
>       53.41         push   %rbp
> 
>        0.63         mov    %rsp,%rbp
>        0.31         sub    $0x170,%rsp
>        1.93         sub    $0x28,%rbp
>        7.02         mov    %rbx,0x0(%rbp)
>        3.20         mov    %r13,0x8(%rbp)
>        1.07         mov    %r14,0x10(%rbp)
>        0.61         mov    %r15,0x18(%rbp)
>        0.11         xor    %eax,%eax
>        1.29         mov    %rax,0x20(%rbp)
>        0.11         mov    %rdi,%rbx
>                    return bpf_get_current_pid_tgid();
>        2.02       → callq  *ffffffffda6776d9
>        2.76         mov    %eax,-0x148(%rbp)
>                     mov    %rbp,%rsi
>                   int sys_enter(struct syscall_enter_args *args)
>                     add    $0xfffffffffffffeb8,%rsi
>                    return bpf_map_lookup_elem(pids, &pid) != NULL;
>                     movabs $0xffff975ac2607800,%rdi
> 
>        1.26       → callq  *ffffffffda6789e9
>                     cmp    $0x0,%rax
>        2.43       → je     0
>                     add    $0x38,%rax
>        0.21         xor    %r13d,%r13d
>                    if (pid_filter__has(&pids_filtered, getpid()))
>        0.81         cmp    $0x0,%rax
>                   → jne    0
>                     mov    %rbp,%rdi
>                    probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
>        2.22         add    $0xfffffffffffffeb8,%rdi
>        0.11         mov    $0x40,%esi
>        0.32         mov    %rbx,%rdx
>        2.74       → callq  *ffffffffda658409
>                    syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
>        0.22         mov    %rbp,%rsi
>        1.69         add    $0xfffffffffffffec0,%rsi
>                    syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
>                     movabs $0xffff975bfcd36000,%rdi
> 
>                     add    $0xd0,%rdi
>        0.21         mov    0x0(%rsi),%eax
>        0.93         cmp    $0x200,%rax
>                   → jae    0
>        0.10         shl    $0x3,%rax
> 
>        0.11         add    %rdi,%rax
>        0.11       → jmp    0
>                     xor    %eax,%eax
>                    if (syscall == NULL || !syscall->enabled)
>        1.07         cmp    $0x0,%rax
>                   → je     0
>                    if (syscall == NULL || !syscall->enabled)
>        6.57         movzbq 0x0(%rax),%rdi
> 
>                    if (syscall == NULL || !syscall->enabled)
>                     cmp    $0x0,%rdi
>        0.95       → je     0
>                     mov    $0x40,%r8d
>                    switch (augmented_args.args.syscall_nr) {
>                     mov    -0x140(%rbp),%rdi
>                    switch (augmented_args.args.syscall_nr) {
>                     cmp    $0x2,%rdi
>                   → je     0
>                     cmp    $0x101,%rdi
>                   → je     0
>                     cmp    $0x15,%rdi
>                   → jne    0
>                    case SYS_OPEN:   filename_arg = (const void *)args->args[0];
>                     mov    0x10(%rbx),%rdx
>                   → jmp    0
>                    case SYS_OPENAT: filename_arg = (const void *)args->args[1];
>                     mov    0x18(%rbx),%rdx
>                    if (filename_arg != NULL) {
>                     cmp    $0x0,%rdx
>                   → je     0
>                     xor    %edi,%edi
>                            augmented_args.filename.reserved = 0;
>                     mov    %edi,-0x104(%rbp)
>                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
>                     mov    %rbp,%rdi
>                     add    $0xffffffffffffff00,%rdi
>                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
>                     mov    $0x100,%esi
>                   → callq  *ffffffffda658499
>                     mov    $0x148,%r8d
>                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
>                     mov    %eax,-0x108(%rbp)
>                            augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
>                     mov    %rax,%rdi
>                     shl    $0x20,%rdi
> 
>                     shr    $0x20,%rdi
> 
>                            if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
>                     cmp    $0xff,%rdi
>                   → ja     0
>                                    len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
>                     add    $0x48,%rax
>                                    len &= sizeof(augmented_args.filename.value) - 1;
>                     and    $0xff,%rax
>                     mov    %rax,%r8
>                     mov    %rbp,%rcx
>                    return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
>                     add    $0xfffffffffffffeb8,%rcx
>                     mov    %rbx,%rdi
>                     movabs $0xffff975fbd72d800,%rsi
> 
>                     mov    $0xffffffff,%edx
>                   → callq  *ffffffffda658ad9
>                     mov    %rax,%r13
>                   }
>                     mov    %r13,%rax
>        0.72         mov    0x0(%rbp),%rbx
>                     mov    0x8(%rbp),%r13
>        1.16         mov    0x10(%rbp),%r14
>        0.10         mov    0x18(%rbp),%r15
>        0.42         add    $0x28,%rbp
>        0.54         leaveq
>        0.54       ← retq
>      #
> 
>    Please see 'man perf-config' to see how to control what should be seen,
>    via ~/.perfconfig [annotate] section, for instance, one can suppress the
>    source code and see just the disassembly, etc.
> 
>    Alternatively, use the TUI bu just using 'perf annotate', press
>    '/bpf_prog' to see the bpf symbols, press enter and do the interactive
>    annotation, which allows for dumping to a file after selecting the
>    the various output tunables, for instance, the above without source code
>    intermixed, plus showing all the instruction offsets:
> 
>      # perf annotate bpf_prog_819967866022f1e1_sys_enter
> 
>    Then press: 's' to hide the source code + 'O' twice to show all
>    instruction offsets, then 'P' to print to the
>    bpf_prog_819967866022f1e1_sys_enter.annotation file, which will have:
> 
>      # cat bpf_prog_819967866022f1e1_sys_enter.annotation
>      bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
>      Event: cycles:ppp
> 
>       53.41    0:   push   %rbp
> 
>        0.63    1:   mov    %rsp,%rbp
>        0.31    4:   sub    $0x170,%rsp
>        1.93    b:   sub    $0x28,%rbp
>        7.02    f:   mov    %rbx,0x0(%rbp)
>        3.20   13:   mov    %r13,0x8(%rbp)
>        1.07   17:   mov    %r14,0x10(%rbp)
>        0.61   1b:   mov    %r15,0x18(%rbp)
>        0.11   1f:   xor    %eax,%eax
>        1.29   21:   mov    %rax,0x20(%rbp)
>        0.11   25:   mov    %rdi,%rbx
>        2.02   28: → callq  *ffffffffda6776d9
>        2.76   2d:   mov    %eax,-0x148(%rbp)
>               33:   mov    %rbp,%rsi
>               36:   add    $0xfffffffffffffeb8,%rsi
>               3d:   movabs $0xffff975ac2607800,%rdi
> 
>        1.26   47: → callq  *ffffffffda6789e9
>               4c:   cmp    $0x0,%rax
>        2.43   50: → je     0
>               52:   add    $0x38,%rax
>        0.21   56:   xor    %r13d,%r13d
>        0.81   59:   cmp    $0x0,%rax
>               5d: → jne    0
>               63:   mov    %rbp,%rdi
>        2.22   66:   add    $0xfffffffffffffeb8,%rdi
>        0.11   6d:   mov    $0x40,%esi
>        0.32   72:   mov    %rbx,%rdx
>        2.74   75: → callq  *ffffffffda658409
>        0.22   7a:   mov    %rbp,%rsi
>        1.69   7d:   add    $0xfffffffffffffec0,%rsi
>               84:   movabs $0xffff975bfcd36000,%rdi
> 
>               8e:   add    $0xd0,%rdi
>        0.21   95:   mov    0x0(%rsi),%eax
>        0.93   98:   cmp    $0x200,%rax
>               9f: → jae    0
>        0.10   a1:   shl    $0x3,%rax
> 
>        0.11   a5:   add    %rdi,%rax
>        0.11   a8: → jmp    0
>               aa:   xor    %eax,%eax
>        1.07   ac:   cmp    $0x0,%rax
>               b0: → je     0
>        6.57   b6:   movzbq 0x0(%rax),%rdi
> 
>               bb:   cmp    $0x0,%rdi
>        0.95   bf: → je     0
>               c5:   mov    $0x40,%r8d
>               cb:   mov    -0x140(%rbp),%rdi
>               d2:   cmp    $0x2,%rdi
>               d6: → je     0
>               d8:   cmp    $0x101,%rdi
>               df: → je     0
>               e1:   cmp    $0x15,%rdi
>               e5: → jne    0
>               e7:   mov    0x10(%rbx),%rdx
>               eb: → jmp    0
>               ed:   mov    0x18(%rbx),%rdx
>               f1:   cmp    $0x0,%rdx
>               f5: → je     0
>               f7:   xor    %edi,%edi
>               f9:   mov    %edi,-0x104(%rbp)
>               ff:   mov    %rbp,%rdi
>              102:   add    $0xffffffffffffff00,%rdi
>              109:   mov    $0x100,%esi
>              10e: → callq  *ffffffffda658499
>              113:   mov    $0x148,%r8d
>              119:   mov    %eax,-0x108(%rbp)
>              11f:   mov    %rax,%rdi
>              122:   shl    $0x20,%rdi
> 
>              126:   shr    $0x20,%rdi
> 
>              12a:   cmp    $0xff,%rdi
>              131: → ja     0
>              133:   add    $0x48,%rax
>              137:   and    $0xff,%rax
>              13d:   mov    %rax,%r8
>              140:   mov    %rbp,%rcx
>              143:   add    $0xfffffffffffffeb8,%rcx
>              14a:   mov    %rbx,%rdi
>              14d:   movabs $0xffff975fbd72d800,%rsi
> 
>              157:   mov    $0xffffffff,%edx
>              15c: → callq  *ffffffffda658ad9
>              161:   mov    %rax,%r13
>              164:   mov    %r13,%rax
>        0.72  167:   mov    0x0(%rbp),%rbx
>              16b:   mov    0x8(%rbp),%r13
>        1.16  16f:   mov    0x10(%rbp),%r14
>        0.10  173:   mov    0x18(%rbp),%r15
>        0.42  177:   add    $0x28,%rbp
>        0.54  17b:   leaveq
>        0.54  17c: ← retq
> 
>    Another cool way to test all this is to symple use 'perf top' look for
>    those symbols, go there and press enter, annotate it live :-)
> 
>    Signed-off-by: Song Liu <songliubraving@fb.com>
>    Reviewed-by: Jiri Olsa <jolsa@kernel.org>
>    Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
>    Cc: Alexei Starovoitov <ast@kernel.org>
>    Cc: Daniel Borkmann <daniel@iogearbox.net>
>    Cc: Namhyung Kim <namhyung@kernel.org>
>    Cc: Peter Zijlstra <peterz@infradead.org>
>    Cc: Stanislav Fomichev <sdf@google.com>
>    Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
>    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [WORKS!] Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19 16:51             ` Song Liu
@ 2019-03-19 16:55               ` Arnaldo Carvalho de Melo
  2019-03-19 17:07                 ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 16:55 UTC (permalink / raw)
  To: Song Liu
  Cc: Arnaldo Carvalho de Melo, bpf, Networking, linux-kernel,
	Alexei Starovoitov, Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 04:51:44PM +0000, Song Liu escreveu:
> 
> 
> > On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > 
> > Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu:
> >> 
> >> Now the test is really being performed, the test-all.bin feature
> >> detection fast path is working, proceeding.
> > 
> > Now it all works, really nice!
> > 
> > I added a 'Committer testing' section with all the steps to test this
> > and pushed to:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f
> 
> Thanks Arnaldo! This looks great!
> 
> I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch
> and resend. 

I just found one new bug, that may appear now since I took a series of
fixes found by gcc's ASan feature, i.e. on the exit path we're crashing
on:

[root@quaco ~]# perf top
perf: Segmentation fault
-------- backtrace --------
perf[0x5a785a]
/lib64/libc.so.6(+0x385bf)[0x7fd68443c5bf]
perf(rb_first+0x2b)[0x4d6eeb]
perf(dso__delete+0xb7)[0x4dffb7]
perf[0x4f9e37]
perf(perf_session__delete+0x64)[0x504df4]
perf(cmd_top+0x1957)[0x454467]
perf[0x4aad18]
perf(main+0x61c)[0x42ec7c]
/lib64/libc.so.6(__libc_start_main+0xf2)[0x7fd684428412]
perf(_start+0x2d)[0x42eead]
[root@quaco ~]#
[root@quaco ~]# addr2line -fe ~/bin/perf 0x4dffb7
dso_cache__free
/home/acme/git/perf/tools/perf/util/dso.c:713


And that is because of that union:

+       union {
+               /* dso data file */
+               struct {
+                       struct rb_root   cache;
+                       int              fd;
+                       int              status;
+                       u32              status_seen;
+                       size_t           file_size;
+                       struct list_head open_entry;
+                       u64              debug_frame_offset;
+                       u64              eh_frame_hdr_offset;
+               } data;
+               /* bpf prog information */
+               struct {
+                       u32             id;
+                       u32             sub_id;
+                       struct perf_env *env;
+               } bpf_prog;
+       };


On the dso exit path, it is trying to traverse the data.cache rbtree,
when what is that is that bpf_prog.id, etc, I'll just remove the union
for now, later we can do the data.cache access or bpf_prog based on some
other test.

^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [WORKS!] Re: [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
  2019-03-19 16:55               ` Arnaldo Carvalho de Melo
@ 2019-03-19 17:07                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-19 17:07 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Song Liu, bpf, Networking, linux-kernel, Alexei Starovoitov,
	Daniel Borkmann, Kernel Team, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Namhyung Kim,
	Stanislav Fomichev

Em Tue, Mar 19, 2019 at 01:55:31PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Mar 19, 2019 at 04:51:44PM +0000, Song Liu escreveu:
> > 
> > 
> > > On Mar 19, 2019, at 7:52 AM, Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com> wrote:
> > > 
> > > Em Tue, Mar 19, 2019 at 11:14:35AM -0300, Arnaldo Carvalho de Melo escreveu:
> > >> 
> > >> Now the test is really being performed, the test-all.bin feature
> > >> detection fast path is working, proceeding.
> > > 
> > > Now it all works, really nice!
> > > 
> > > I added a 'Committer testing' section with all the steps to test this
> > > and pushed to:
> > > 
> > > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/commit/?h=perf/core&id=6530d44e7dc1d41c73fe70b9e6ea1b9cabebb57f
> > 
> > Thanks Arnaldo! This looks great!
> > 
> > I will rebase https://lkml.org/lkml/2019/3/14/681 on top of this branch
> > and resend. 
> 
> I just found one new bug, that may appear now since I took a series of
> fixes found by gcc's ASan feature, i.e. on the exit path we're crashing
> on:
> 
> [root@quaco ~]# perf top
> perf: Segmentation fault
> -------- backtrace --------
> perf[0x5a785a]
> /lib64/libc.so.6(+0x385bf)[0x7fd68443c5bf]
> perf(rb_first+0x2b)[0x4d6eeb]
> perf(dso__delete+0xb7)[0x4dffb7]
> perf[0x4f9e37]
> perf(perf_session__delete+0x64)[0x504df4]
> perf(cmd_top+0x1957)[0x454467]
> perf[0x4aad18]
> perf(main+0x61c)[0x42ec7c]
> /lib64/libc.so.6(__libc_start_main+0xf2)[0x7fd684428412]
> perf(_start+0x2d)[0x42eead]
> [root@quaco ~]#
> [root@quaco ~]# addr2line -fe ~/bin/perf 0x4dffb7
> dso_cache__free
> /home/acme/git/perf/tools/perf/util/dso.c:713
> 
> 
> And that is because of that union:
> 
> +       union {
> +               /* dso data file */
> +               struct {
> +                       struct rb_root   cache;
> +                       int              fd;
> +                       int              status;
> +                       u32              status_seen;
> +                       size_t           file_size;
> +                       struct list_head open_entry;
> +                       u64              debug_frame_offset;
> +                       u64              eh_frame_hdr_offset;
> +               } data;
> +               /* bpf prog information */
> +               struct {
> +                       u32             id;
> +                       u32             sub_id;
> +                       struct perf_env *env;
> +               } bpf_prog;
> +       };
> 
> 
> On the dso exit path, it is trying to traverse the data.cache rbtree,
> when what is that is that bpf_prog.id, etc, I'll just remove the union
> for now, later we can do the data.cache access or bpf_prog based on some
> other test.

One more on 32-bit arches, a uintptr_t case for the jited_ksyms on the
BPF annotate patch, will fix.

- Arnaldo


^ permalink raw reply	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs
  2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
                   ` (15 preceding siblings ...)
  2019-03-12 13:12 ` [PATCH v9 perf,bpf 00/15] perf annotation of " Jiri Olsa
@ 2019-03-21  9:10 ` Jiri Olsa
  2019-03-21 14:12   ` Arnaldo Carvalho de Melo
  16 siblings, 1 reply; 100+ messages in thread
From: Jiri Olsa @ 2019-03-21  9:10 UTC (permalink / raw)
  To: Song Liu
  Cc: bpf, netdev, linux-kernel, ast, daniel, kernel-team, peterz,
	acme, jolsa, namhyung, sdf

On Mon, Mar 11, 2019 at 10:30:36PM -0700, Song Liu wrote:
> Changes v8 to v9:
> 1. Rebase on top of torvalds/master:
>     commit ea295481b6e313b4ea3ca2720ffcafd6005b5643 ;
> 2. Change perf-record option --bpf-event to --no-bpf-event.
> 
> Changes v7 to v8:
> 1. Address issues suggested by Jiri and Stanislav.
> 
> Changes v6 to v7:
> 1. Fix minor issues suggested by Jiri.
> 
> Changes v5 to v6:
> 1. Improve side band evlist interface;
> 2. Minor style fixes.
> 
> Changes v4 to v5:
> 1. Rebase to latest bpf-next;
> 2. Add dependency of 94816add0005 from Arnaldo's tree;
> 3. More details in change logs;
> 4. Add perf_env__init() to init bpf related lock and rbtrees;
> 5. Small clean ups.
> 
> Changes v3 to v4:
> 1. Incorporate feedbacks from Jiri and Namhyung;
> 2. Fixed compilation error with different feature-disassembler-four-args;
> 3. Split some patches to smaller patches;
> 4. Improved error handleing in symbol__disassemble_bpf();
> 5. Made side band thread more generic;
> 6. Added comments as suggested.
> 
> Changes v2 to v3:
> 1. Remove unnecessary include in header files;
> 2. Improved error handling;
> 3. Better naming of functions, variables, etc.;
> 4. Enable bpf events by default for perf-top.
> 
> Changes v1 to v2:
> 1. Fix compilation error with different feature-disassembler-four-args;
> 2. Fix a segfault in perf-record;
> 3. Split patches 5/9 and 6/9 so that perf_env changes and perf.data changes
>    are in separate patches.
> 
> This series enables annotation of BPF programs in perf.
> 
> perf tool gathers information via sys_bpf and (optionally) stores them in
> perf.data as headers.
> 
> Patch 1/15 changes --bpf-event option to --no-bpf-event;
> Patch 2/15 to 4/15 introduce new helper functions and use them in perf and
>      bpftool;
> Patch 5/15 to 9/15 saves information of bpf program in perf_env;
> Patch 10/15 adds --bpf-event options to perf-top;
> Patch 11/15 to 13/15 enables annotation of bpf progs based on information
>      gathered in 5/15 to 9/15;
> Patch 14/15 introduces side band polling thread that gathers information
>      for special kernel events during perf-record or perf-top.
> Patch 15/15 handles information of short living BPF program using the new
>      side band polling thread.
> 
> Commands tested during developments are perf-top, perf-record, perf-report,
> and perf-annotate.
> 
> This set is also available at:
> 
> https://github.com/liu-song-6/linux/tree/bpf-annotation-v9
> 
> Thanks!!
> 
> Song Liu (15):
>   perf-record: replace option --bpf-event with --no-bpf-event
>   bpf: libbpf: introduce bpf_program__get_prog_info_linear()
>   bpf: bpftool: use bpf_program__get_prog_info_linear() in
>     prog.c:do_dump()
>   perf, bpf: synthesize bpf events with
>     bpf_program__get_prog_info_linear()
>   perf: change prototype of perf_event__synthesize_bpf_events()
>   perf, bpf: save bpf_prog_info in a rbtree in perf_env
>   perf, bpf: save bpf_prog_info information as headers to perf.data
>   perf, bpf: save btf in a rbtree in perf_env
>   perf, bpf: save btf information as headers to perf.data
>   perf-top: add option --no-bpf-event
>   perf: add -lopcodes to feature-libbfd
>   perf, bpf: enable annotation of bpf program
>   perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
>   perf: introduce side band thread
>   perf, bpf: save bpf_prog_info and btf of short living bpf programs

it still crashes on standard user, like:


[jolsa@krava perf]$ ./perf record  ./perf bench sched messaging
# Running 'sched/messaging' benchmark:
# 20 sender and receiver processes per group
# 10 groups == 400 processes run

     Total time: 0.143 [sec]
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.282 MB perf.data (6341 samples) ]
perf: Segmentation fault
Obtained 14 stack frames.
./perf(dump_stack+0x2d) [0x531f8b]
./perf(sighandler_dump_stack+0x2d) [0x53206b]
./perf() [0x444cd9]
/lib64/libc.so.6(+0x36f2f) [0x7f64a0ef2f2f]
/lib64/libpthread.so.0(+0x88bc) [0x7f64a32518bc]
./perf(perf_evlist__stop_sb_thread+0x47) [0x4f30fc]
./perf() [0x447909]
./perf(cmd_record+0x815) [0x448afc]
./perf() [0x4d4c52]
./perf() [0x4d4ebf]
./perf() [0x4d500e]
./perf(main+0x267) [0x4d537a]
/lib64/libc.so.6(__libc_start_main+0xea) [0x7f64a0edf11a]
./perf(_start+0x29) [0x42cbd9]
Segmentation fault (core dumped)


the reason is that you try to open system wide counter
and that's not allow for standard user.. so the thread
won't get started, but there's code to stop it unconsidtionaly
which crashes


the patch below fixes that for me, but I guess we want
to check if th eerror was -EACCESS, if not we should fail

jirka


---
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 08832fdaa26b..766059bf26ee 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1240,7 +1240,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 	if (!opts->no_bpf_event)
 		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
-	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
+	if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target))
+		opts->no_bpf_event = true;
 
 	err = record__synthesize(rec, false);
 	if (err < 0)
@@ -1493,7 +1494,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 out_delete_session:
 	perf_session__delete(session);
 
-	perf_evlist__stop_sb_thread(sb_evlist);
+	if (!opts->no_bpf_event)
+		perf_evlist__stop_sb_thread(sb_evlist);
 	return status;
 }
 

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* Re: [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs
  2019-03-21  9:10 ` Jiri Olsa
@ 2019-03-21 14:12   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 100+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-03-21 14:12 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Song Liu, bpf, netdev, linux-kernel, ast, daniel, kernel-team,
	peterz, acme, jolsa, namhyung, sdf

Em Thu, Mar 21, 2019 at 10:10:16AM +0100, Jiri Olsa escreveu:
> On Mon, Mar 11, 2019 at 10:30:36PM -0700, Song Liu wrote:
> > Changes v8 to v9:
> > 1. Rebase on top of torvalds/master:
> >     commit ea295481b6e313b4ea3ca2720ffcafd6005b5643 ;
> > 2. Change perf-record option --bpf-event to --no-bpf-event.
> > 
> > Changes v7 to v8:
> > 1. Address issues suggested by Jiri and Stanislav.
> > 
> > Changes v6 to v7:
> > 1. Fix minor issues suggested by Jiri.
> > 
> > Changes v5 to v6:
> > 1. Improve side band evlist interface;
> > 2. Minor style fixes.
> > 
> > Changes v4 to v5:
> > 1. Rebase to latest bpf-next;
> > 2. Add dependency of 94816add0005 from Arnaldo's tree;
> > 3. More details in change logs;
> > 4. Add perf_env__init() to init bpf related lock and rbtrees;
> > 5. Small clean ups.
> > 
> > Changes v3 to v4:
> > 1. Incorporate feedbacks from Jiri and Namhyung;
> > 2. Fixed compilation error with different feature-disassembler-four-args;
> > 3. Split some patches to smaller patches;
> > 4. Improved error handleing in symbol__disassemble_bpf();
> > 5. Made side band thread more generic;
> > 6. Added comments as suggested.
> > 
> > Changes v2 to v3:
> > 1. Remove unnecessary include in header files;
> > 2. Improved error handling;
> > 3. Better naming of functions, variables, etc.;
> > 4. Enable bpf events by default for perf-top.
> > 
> > Changes v1 to v2:
> > 1. Fix compilation error with different feature-disassembler-four-args;
> > 2. Fix a segfault in perf-record;
> > 3. Split patches 5/9 and 6/9 so that perf_env changes and perf.data changes
> >    are in separate patches.
> > 
> > This series enables annotation of BPF programs in perf.
> > 
> > perf tool gathers information via sys_bpf and (optionally) stores them in
> > perf.data as headers.
> > 
> > Patch 1/15 changes --bpf-event option to --no-bpf-event;
> > Patch 2/15 to 4/15 introduce new helper functions and use them in perf and
> >      bpftool;
> > Patch 5/15 to 9/15 saves information of bpf program in perf_env;
> > Patch 10/15 adds --bpf-event options to perf-top;
> > Patch 11/15 to 13/15 enables annotation of bpf progs based on information
> >      gathered in 5/15 to 9/15;
> > Patch 14/15 introduces side band polling thread that gathers information
> >      for special kernel events during perf-record or perf-top.
> > Patch 15/15 handles information of short living BPF program using the new
> >      side band polling thread.
> > 
> > Commands tested during developments are perf-top, perf-record, perf-report,
> > and perf-annotate.
> > 
> > This set is also available at:
> > 
> > https://github.com/liu-song-6/linux/tree/bpf-annotation-v9
> > 
> > Thanks!!
> > 
> > Song Liu (15):
> >   perf-record: replace option --bpf-event with --no-bpf-event
> >   bpf: libbpf: introduce bpf_program__get_prog_info_linear()
> >   bpf: bpftool: use bpf_program__get_prog_info_linear() in
> >     prog.c:do_dump()
> >   perf, bpf: synthesize bpf events with
> >     bpf_program__get_prog_info_linear()
> >   perf: change prototype of perf_event__synthesize_bpf_events()
> >   perf, bpf: save bpf_prog_info in a rbtree in perf_env
> >   perf, bpf: save bpf_prog_info information as headers to perf.data
> >   perf, bpf: save btf in a rbtree in perf_env
> >   perf, bpf: save btf information as headers to perf.data
> >   perf-top: add option --no-bpf-event
> >   perf: add -lopcodes to feature-libbfd
> >   perf, bpf: enable annotation of bpf program
> >   perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
> >   perf: introduce side band thread
> >   perf, bpf: save bpf_prog_info and btf of short living bpf programs
> 
> it still crashes on standard user, like:
> 
> 
> [jolsa@krava perf]$ ./perf record  ./perf bench sched messaging
> # Running 'sched/messaging' benchmark:
> # 20 sender and receiver processes per group
> # 10 groups == 400 processes run
> 
>      Total time: 0.143 [sec]
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.282 MB perf.data (6341 samples) ]
> perf: Segmentation fault
> Obtained 14 stack frames.
> ./perf(dump_stack+0x2d) [0x531f8b]
> ./perf(sighandler_dump_stack+0x2d) [0x53206b]
> ./perf() [0x444cd9]
> /lib64/libc.so.6(+0x36f2f) [0x7f64a0ef2f2f]
> /lib64/libpthread.so.0(+0x88bc) [0x7f64a32518bc]
> ./perf(perf_evlist__stop_sb_thread+0x47) [0x4f30fc]
> ./perf() [0x447909]
> ./perf(cmd_record+0x815) [0x448afc]
> ./perf() [0x4d4c52]
> ./perf() [0x4d4ebf]
> ./perf() [0x4d500e]
> ./perf(main+0x267) [0x4d537a]
> /lib64/libc.so.6(__libc_start_main+0xea) [0x7f64a0edf11a]
> ./perf(_start+0x29) [0x42cbd9]
> Segmentation fault (core dumped)
> 
> 
> the reason is that you try to open system wide counter
> and that's not allow for standard user.. so the thread
> won't get started, but there's code to stop it unconsidtionaly
> which crashes
> 
> 
> the patch below fixes that for me, but I guess we want
> to check if th eerror was -EACCESS, if not we should fail

Right, I'll apply your patch as a stop-gap solution so that I can
proceed with pushing what we already have, and then we need to polish
this thing for good.


- Arnaldo
 
> jirka
> 
> 
> ---
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 08832fdaa26b..766059bf26ee 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -1240,7 +1240,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
>  
>  	if (!opts->no_bpf_event)
>  		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
> -	perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target);
> +	if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target))
> +		opts->no_bpf_event = true;
>  
>  	err = record__synthesize(rec, false);
>  	if (err < 0)
> @@ -1493,7 +1494,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
>  out_delete_session:
>  	perf_session__delete(session);
>  
> -	perf_evlist__stop_sb_thread(sb_evlist);
> +	if (!opts->no_bpf_event)
> +		perf_evlist__stop_sb_thread(sb_evlist);
>  	return status;
>  }
>  

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf record: Replace option --bpf-event with --no-bpf-event
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event Song Liu
@ 2019-03-22 22:35   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:35 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mingo, songliubraving, tglx, linux-kernel, hpa, acme, ast, sdf,
	daniel, jolsa, namhyung, peterz

Commit-ID:  71184c6ab7e60fd59d8dbc8fed62a1c753dc4934
Gitweb:     https://git.kernel.org/tip/71184c6ab7e60fd59d8dbc8fed62a1c753dc4934
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:37 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

perf record: Replace option --bpf-event with --no-bpf-event

Currently, monitoring of BPF programs through bpf_event is off by
default for 'perf record'.

To turn it on, the user need to use option "--bpf-event".  As BPF gets
wider adoption in different subsystems, this option becomes
inconvenient.

This patch makes bpf_event on by default, and adds option "--no-bpf-event"
to turn it off. Since option --bpf-event is not released yet, it is safe
to remove it.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: kernel-team@fb.com
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-2-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-record.c | 2 +-
 tools/perf/perf.h           | 2 +-
 tools/perf/util/bpf-event.c | 2 +-
 tools/perf/util/evsel.c     | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e7144a1c1c82..f29874192d3e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1891,7 +1891,7 @@ static struct option __record_options[] = {
 	OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
 		    "synthesize non-sample events at the end of output"),
 	OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
-	OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"),
+	OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "record bpf events"),
 	OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
 		    "Fail if the specified frequency can't be used"),
 	OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index b120e547ddc7..c59743def8d3 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -66,7 +66,7 @@ struct record_opts {
 	bool	     ignore_missing_thread;
 	bool	     strict_freq;
 	bool	     sample_id;
-	bool	     bpf_event;
+	bool	     no_bpf_event;
 	unsigned int freq;
 	unsigned int mmap_pages;
 	unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 028c8ec1f62a..ea012b735a37 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -187,7 +187,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
 	}
 
 	/* Synthesize PERF_RECORD_BPF_EVENT */
-	if (opts->bpf_event) {
+	if (!opts->no_bpf_event) {
 		*bpf_event = (struct bpf_event){
 			.header = {
 				.type = PERF_RECORD_BPF_EVENT,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1a2023da5d9c..7835e05f0c0a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1036,7 +1036,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
 	attr->mmap2 = track && !perf_missing_features.mmap2;
 	attr->comm  = track;
 	attr->ksymbol = track && !perf_missing_features.ksymbol;
-	attr->bpf_event = track && opts->bpf_event &&
+	attr->bpf_event = track && !opts->no_bpf_event &&
 		!perf_missing_features.bpf_event;
 
 	if (opts->record_namespaces)

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] tools lib bpf: Introduce bpf_program__get_prog_info_linear()
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
  2019-03-12 13:50   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:36   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:36 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: hpa, peterz, linux-kernel, jolsa, ast, mingo, tglx,
	songliubraving, daniel, sdf, acme, namhyung

Commit-ID:  34be16466d4dc06f3d604dafbcdb3327b72e78da
Gitweb:     https://git.kernel.org/tip/34be16466d4dc06f3d604dafbcdb3327b72e78da
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:38 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

tools lib bpf: Introduce bpf_program__get_prog_info_linear()

Currently, bpf_prog_info includes 9 arrays. The user has the option to
fetch any combination of these arrays. However, this requires a lot of
handling.

This work becomes more tricky when we need to store bpf_prog_info to a
file, because these arrays are allocated independently.

This patch introduces 'struct bpf_prog_info_linear', which stores arrays
of bpf_prog_info in continuous memory.

Helper functions are introduced to unify the work to get different sets
of bpf_prog_info.  Specifically, bpf_program__get_prog_info_linear()
allows the user to select which arrays to fetch, and handles details for
the user.

Please see the comments right before 'enum bpf_prog_info_array' for more
details and examples.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lkml.kernel.org/r/ce92c091-e80d-a0c1-4aa0-987706c42b20@iogearbox.net
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: kernel-team@fb.com
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-3-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c   | 251 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h   |  63 ++++++++++++
 tools/lib/bpf/libbpf.map |   3 +
 3 files changed, 317 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4884557aa17f..8fb6e89b4b2c 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
 # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
 #endif
 
+static inline __u64 ptr_to_u64(const void *ptr)
+{
+	return (__u64) (unsigned long) ptr;
+}
+
 struct bpf_capabilities {
 	/* v4.14: kernel support for program & map names. */
 	__u32 name:1;
@@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
 	ring_buffer_write_tail(header, data_tail);
 	return ret;
 }
+
+struct bpf_prog_info_array_desc {
+	int	array_offset;	/* e.g. offset of jited_prog_insns */
+	int	count_offset;	/* e.g. offset of jited_prog_len */
+	int	size_offset;	/* > 0: offset of rec size,
+				 * < 0: fix size of -size_offset
+				 */
+};
+
+static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
+	[BPF_PROG_INFO_JITED_INSNS] = {
+		offsetof(struct bpf_prog_info, jited_prog_insns),
+		offsetof(struct bpf_prog_info, jited_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_XLATED_INSNS] = {
+		offsetof(struct bpf_prog_info, xlated_prog_insns),
+		offsetof(struct bpf_prog_info, xlated_prog_len),
+		-1,
+	},
+	[BPF_PROG_INFO_MAP_IDS] = {
+		offsetof(struct bpf_prog_info, map_ids),
+		offsetof(struct bpf_prog_info, nr_map_ids),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_JITED_KSYMS] = {
+		offsetof(struct bpf_prog_info, jited_ksyms),
+		offsetof(struct bpf_prog_info, nr_jited_ksyms),
+		-(int)sizeof(__u64),
+	},
+	[BPF_PROG_INFO_JITED_FUNC_LENS] = {
+		offsetof(struct bpf_prog_info, jited_func_lens),
+		offsetof(struct bpf_prog_info, nr_jited_func_lens),
+		-(int)sizeof(__u32),
+	},
+	[BPF_PROG_INFO_FUNC_INFO] = {
+		offsetof(struct bpf_prog_info, func_info),
+		offsetof(struct bpf_prog_info, nr_func_info),
+		offsetof(struct bpf_prog_info, func_info_rec_size),
+	},
+	[BPF_PROG_INFO_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, line_info),
+		offsetof(struct bpf_prog_info, nr_line_info),
+		offsetof(struct bpf_prog_info, line_info_rec_size),
+	},
+	[BPF_PROG_INFO_JITED_LINE_INFO] = {
+		offsetof(struct bpf_prog_info, jited_line_info),
+		offsetof(struct bpf_prog_info, nr_jited_line_info),
+		offsetof(struct bpf_prog_info, jited_line_info_rec_size),
+	},
+	[BPF_PROG_INFO_PROG_TAGS] = {
+		offsetof(struct bpf_prog_info, prog_tags),
+		offsetof(struct bpf_prog_info, nr_prog_tags),
+		-(int)sizeof(__u8) * BPF_TAG_SIZE,
+	},
+
+};
+
+static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u32)];
+	return -(int)offset;
+}
+
+static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		return array[offset / sizeof(__u64)];
+	return -(int)offset;
+}
+
+static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
+					 __u32 val)
+{
+	__u32 *array = (__u32 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u32)] = val;
+}
+
+static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
+					 __u64 val)
+{
+	__u64 *array = (__u64 *)info;
+
+	if (offset >= 0)
+		array[offset / sizeof(__u64)] = val;
+}
+
+struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info info = {};
+	__u32 info_len = sizeof(info);
+	__u32 data_len = 0;
+	int i, err;
+	void *ptr;
+
+	if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
+		return ERR_PTR(-EINVAL);
+
+	/* step 1: get array dimensions */
+	err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 2: calculate total size of all arrays */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		bool include_array = (arrays & (1UL << i)) > 0;
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		desc = bpf_prog_info_array_desc + i;
+
+		/* kernel is too old to support this field */
+		if (info_len < desc->array_offset + sizeof(__u32) ||
+		    info_len < desc->count_offset + sizeof(__u32) ||
+		    (desc->size_offset > 0 && info_len < desc->size_offset))
+			include_array = false;
+
+		if (!include_array) {
+			arrays &= ~(1UL << i);	/* clear the bit */
+			continue;
+		}
+
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size  = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+
+		data_len += count * size;
+	}
+
+	/* step 3: allocate continuous memory */
+	data_len = roundup(data_len, sizeof(__u64));
+	info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
+	if (!info_linear)
+		return ERR_PTR(-ENOMEM);
+
+	/* step 4: fill data to info_linear->info */
+	info_linear->arrays = arrays;
+	memset(&info_linear->info, 0, sizeof(info));
+	ptr = info_linear->data;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 count, size;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc  = bpf_prog_info_array_desc + i;
+		count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		size  = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->count_offset, count);
+		bpf_prog_info_set_offset_u32(&info_linear->info,
+					     desc->size_offset, size);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset,
+					     ptr_to_u64(ptr));
+		ptr += count * size;
+	}
+
+	/* step 5: call syscall again to get required arrays */
+	err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
+	if (err) {
+		pr_debug("can't get prog info: %s", strerror(errno));
+		free(info_linear);
+		return ERR_PTR(-EFAULT);
+	}
+
+	/* step 6: verify the data */
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u32 v1, v2;
+
+		if ((arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->count_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in element count\n", __func__);
+
+		v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+		v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+						   desc->size_offset);
+		if (v1 != v2)
+			pr_warning("%s: mismatch in rec size\n", __func__);
+	}
+
+	/* step 7: update info_len and data_len */
+	info_linear->info_len = sizeof(struct bpf_prog_info);
+	info_linear->data_len = data_len;
+
+	return info_linear;
+}
+
+void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		addr = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		offs = addr - ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, offs);
+	}
+}
+
+void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
+{
+	int i;
+
+	for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+		struct bpf_prog_info_array_desc *desc;
+		__u64 addr, offs;
+
+		if ((info_linear->arrays & (1UL << i)) == 0)
+			continue;
+
+		desc = bpf_prog_info_array_desc + i;
+		offs = bpf_prog_info_read_offset_u64(&info_linear->info,
+						     desc->array_offset);
+		addr = offs + ptr_to_u64(info_linear->data);
+		bpf_prog_info_set_offset_u64(&info_linear->info,
+					     desc->array_offset, addr);
+	}
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index aa1521a51687..c70785cc8ef5 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -378,6 +378,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
 LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
 				 enum bpf_prog_type prog_type, __u32 ifindex);
 
+/*
+ * Get bpf_prog_info in continuous memory
+ *
+ * struct bpf_prog_info has multiple arrays. The user has option to choose
+ * arrays to fetch from kernel. The following APIs provide an uniform way to
+ * fetch these data. All arrays in bpf_prog_info are stored in a single
+ * continuous memory region. This makes it easy to store the info in a
+ * file.
+ *
+ * Before writing bpf_prog_info_linear to files, it is necessary to
+ * translate pointers in bpf_prog_info to offsets. Helper functions
+ * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
+ * are introduced to switch between pointers and offsets.
+ *
+ * Examples:
+ *   # To fetch map_ids and prog_tags:
+ *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
+ *           (1UL << BPF_PROG_INFO_PROG_TAGS);
+ *   struct bpf_prog_info_linear *info_linear =
+ *           bpf_program__get_prog_info_linear(fd, arrays);
+ *
+ *   # To save data in file
+ *   bpf_program__bpil_addr_to_offs(info_linear);
+ *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
+ *
+ *   # To read data from file
+ *   read(f, info_linear, <proper_size>);
+ *   bpf_program__bpil_offs_to_addr(info_linear);
+ */
+enum bpf_prog_info_array {
+	BPF_PROG_INFO_FIRST_ARRAY = 0,
+	BPF_PROG_INFO_JITED_INSNS = 0,
+	BPF_PROG_INFO_XLATED_INSNS,
+	BPF_PROG_INFO_MAP_IDS,
+	BPF_PROG_INFO_JITED_KSYMS,
+	BPF_PROG_INFO_JITED_FUNC_LENS,
+	BPF_PROG_INFO_FUNC_INFO,
+	BPF_PROG_INFO_LINE_INFO,
+	BPF_PROG_INFO_JITED_LINE_INFO,
+	BPF_PROG_INFO_PROG_TAGS,
+	BPF_PROG_INFO_LAST_ARRAY,
+};
+
+struct bpf_prog_info_linear {
+	/* size of struct bpf_prog_info, when the tool is compiled */
+	__u32			info_len;
+	/* total bytes allocated for data, round up to 8 bytes */
+	__u32			data_len;
+	/* which arrays are included in data */
+	__u64			arrays;
+	struct bpf_prog_info	info;
+	__u8			data[];
+};
+
+LIBBPF_API struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays);
+
+LIBBPF_API void
+bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
+
+LIBBPF_API void
+bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 778a26702a70..f3ce50500cf2 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
 		xsk_socket__delete;
 		xsk_umem__fd;
 		xsk_socket__fd;
+		bpf_program__get_prog_info_linear;
+		bpf_program__bpil_addr_to_offs;
+		bpf_program__bpil_offs_to_addr;
 } LIBBPF_0.0.1;

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
@ 2019-03-22 22:36   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:36 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: daniel, peterz, sdf, ast, linux-kernel, songliubraving, jolsa,
	namhyung, mingo, tglx, acme, hpa

Commit-ID:  cae73f2339231d61022769f09c94e4500e8ad47a
Gitweb:     https://git.kernel.org/tip/cae73f2339231d61022769f09c94e4500e8ad47a
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:39 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()

This patches uses bpf_program__get_prog_info_linear() to simplify the
logic in prog.c do_dump().

Committer testing:

Before:

  # bpftool prog dump xlated id 208 > /tmp/dump.xlated.before
  # bpftool prog dump jited id 208 > /tmp/dump.jited.before
  # bpftool map dump id 107 > /tmp/map.dump.before

After:

  # ~acme/git/perf/tools/bpf/bpftool/bpftool map dump id 107 > /tmp/map.dump.after
  # ~acme/git/perf/tools/bpf/bpftool/bpftool prog dump xlated id 208 > /tmp/dump.xlated.after
  # ~acme/git/perf/tools/bpf/bpftool/bpftool prog dump jited id 208 > /tmp/dump.jited.after
  # diff -u /tmp/dump.xlated.before /tmp/dump.xlated.after
  # diff -u /tmp/dump.jited.before /tmp/dump.jited.after
  # diff -u /tmp/map.dump.before /tmp/map.dump.after
  # ~acme/git/perf/tools/bpf/bpftool/bpftool prog dump xlated id 208
     0: (bf) r6 = r1
     1: (85) call bpf_get_current_pid_tgid#80800
     2: (63) *(u32 *)(r10 -328) = r0
     3: (bf) r2 = r10
     4: (07) r2 += -328
     5: (18) r1 = map[id:107]
     7: (85) call __htab_map_lookup_elem#85680
     8: (15) if r0 == 0x0 goto pc+1
     9: (07) r0 += 56
    10: (b7) r7 = 0
    11: (55) if r0 != 0x0 goto pc+52
    12: (bf) r1 = r10
    13: (07) r1 += -328
    14: (b7) r2 = 64
    15: (bf) r3 = r6
    16: (85) call bpf_probe_read#-46848
    17: (bf) r2 = r10
    18: (07) r2 += -320
    19: (18) r1 = map[id:106]
    21: (07) r1 += 208
    22: (61) r0 = *(u32 *)(r2 +0)
    23: (35) if r0 >= 0x200 goto pc+3
    24: (67) r0 <<= 3
    25: (0f) r0 += r1
    26: (05) goto pc+1
    27: (b7) r0 = 0
    28: (15) if r0 == 0x0 goto pc+35
    29: (71) r1 = *(u8 *)(r0 +0)
    30: (15) if r1 == 0x0 goto pc+33
    31: (b7) r5 = 64
    32: (79) r1 = *(u64 *)(r10 -320)
    33: (15) if r1 == 0x2 goto pc+2
    34: (15) if r1 == 0x101 goto pc+3
    35: (55) if r1 != 0x15 goto pc+19
    36: (79) r3 = *(u64 *)(r6 +16)
    37: (05) goto pc+1
    38: (79) r3 = *(u64 *)(r6 +24)
    39: (15) if r3 == 0x0 goto pc+15
    40: (b7) r1 = 0
    41: (63) *(u32 *)(r10 -260) = r1
    42: (bf) r1 = r10
    43: (07) r1 += -256
    44: (b7) r2 = 256
    45: (85) call bpf_probe_read_str#-46704
    46: (b7) r5 = 328
    47: (63) *(u32 *)(r10 -264) = r0
    48: (bf) r1 = r0
    49: (67) r1 <<= 32
    50: (77) r1 >>= 32
    51: (25) if r1 > 0xff goto pc+3
    52: (07) r0 += 72
    53: (57) r0 &= 255
    54: (bf) r5 = r0
    55: (bf) r4 = r10
    56: (07) r4 += -328
    57: (bf) r1 = r6
    58: (18) r2 = map[id:105]
    60: (18) r3 = 0xffffffff
    62: (85) call bpf_perf_event_output_tp#-45104
    63: (bf) r7 = r0
    64: (bf) r0 = r7
    65: (95) exit
  #

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: kernel-team@fb.com
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-4-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.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 8ef80d65a474..d2be5a06c339 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -401,41 +401,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;
@@ -474,175 +464,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.");
 	}
@@ -655,9 +520,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;
@@ -665,19 +530,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];
@@ -685,17 +550,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)
@@ -707,7 +571,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));
@@ -744,49 +608,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;
 }
 

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Synthesize bpf events with bpf_program__get_prog_info_linear()
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
  2019-03-13 21:00   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:37   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:37 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, mingo, daniel, sdf, ast, hpa, jolsa, acme,
	namhyung, tglx, songliubraving, peterz

Commit-ID:  a742258af131e570a68ad8cf16cd2cc4692675a0
Gitweb:     https://git.kernel.org/tip/a742258af131e570a68ad8cf16cd2cc4692675a0
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:40 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

perf bpf: Synthesize bpf events with bpf_program__get_prog_info_linear()

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.

Commiter notes:

Needed this (for all four variables), suggested by Song, to overcome
build failure on debian experimental cross building to MIPS 32-bit:

  -               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
  +               u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(uintptr_t)(info->prog_tags);

  util/bpf-event.c: In function 'perf_event__synthesize_one_bpf_prog':
  util/bpf-event.c:143:35: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
     u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(info->prog_tags);
                                     ^
  util/bpf-event.c:144:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
     __u32 *prog_lens = (__u32 *)(info->jited_func_lens);
                        ^
  util/bpf-event.c:145:23: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
     __u64 *prog_addrs = (__u64 *)(info->jited_ksyms);
                         ^
  util/bpf-event.c:146:22: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
     void *func_infos = (void *)(info->func_info);
                        ^
  cc1: all warnings being treated as errors

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: kernel-team@fb.com
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-5-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.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 ea012b735a37..e0cbe7f87170 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 *)(uintptr_t)(info->prog_tags);
+		__u32 *prog_lens  = (__u32 *)(uintptr_t)(info->jited_func_lens);
+		__u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms);
+		void *func_infos  = (void *)(uintptr_t)(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;
 }

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Make synthesize_bpf_events() receive perf_session pointer instead of perf_tool
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
@ 2019-03-22 22:37   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:37 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: jolsa, acme, mingo, peterz, sdf, songliubraving, namhyung, hpa,
	linux-kernel, daniel, tglx, ast

Commit-ID:  e5416950454fa79b7bdc86dac45661b97d887c97
Gitweb:     https://git.kernel.org/tip/e5416950454fa79b7bdc86dac45661b97d887c97
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:41 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

perf bpf: Make synthesize_bpf_events() receive perf_session pointer instead of perf_tool

This patch changes the arguments of perf_event__synthesize_bpf_events()
to include perf_session* instead of perf_tool*. perf_session will be
used in the next patch.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-6-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-record.c | 2 +-
 tools/perf/builtin-top.c    | 2 +-
 tools/perf/util/bpf-event.c | 8 +++++---
 tools/perf/util/bpf-event.h | 4 ++--
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f29874192d3e..e79faccd7842 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1114,7 +1114,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 2508a7a552fa..77e6190211d2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1208,7 +1208,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 e0cbe7f87170..5237e8f11997 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -42,7 +43,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,6 +53,7 @@ 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 *info;
 	struct btf *btf = NULL;
 	bool has_btf = false;
@@ -175,7 +177,7 @@ out:
 	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 +211,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..6698683612a7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -15,7 +15,7 @@ struct record_opts;
 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 +27,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)

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Save bpf_prog_info in a rbtree in perf_env
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
  2019-03-12 13:10   ` Jiri Olsa
@ 2019-03-22 22:38   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:38 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: sdf, daniel, mingo, tglx, linux-kernel, jolsa, ast, acme, hpa,
	songliubraving, namhyung, peterz

Commit-ID:  e4378f0cb90be0368c48baad69a99203c58e3196
Gitweb:     https://git.kernel.org/tip/e4378f0cb90be0368c48baad69a99203c58e3196
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:42 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

perf bpf: Save bpf_prog_info in a rbtree in perf_env

bpf_prog_info contains information necessary to annotate bpf programs.

This patch saves bpf_prog_info for bpf programs loaded in the system.

Some big picture of the next few patches:

To fully annotate BPF programs with source code mapping, 4 different
informations are needed:

    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

Before this set, 1) and 2) in the list are already saved to perf.data
file. For BPF programs that are already loaded before perf run, 1) and 2)
are synthesized by perf_event__synthesize_bpf_events(). For short living
BPF programs, 1) and 2) are generated by kernel.

This set handles 3) and 4) from the list. Again, it is necessary to handle
existing BPF program and short living program separately.

This patch handles 3) for exising BPF programs while synthesizing 1) and
2) in perf_event__synthesize_bpf_events(). These data are stored in
perf_env. The next patch saves these data from perf_env to perf.data as
headers.

Similarly, the two patches after the next saves 4) of existing BPF
programs to perf_env and perf.data.

Another patch later will handle 3) and 4) for short living BPF programs
by monitoring 1) and 2) in a dedicate thread.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-7-songliubraving@fb.com
[ set env->bpf_progs.infos_cnt to zero in perf_env__purge_bpf() as noted by jolsa ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/perf.c           |  1 +
 tools/perf/util/bpf-event.c | 30 +++++++++++++++-
 tools/perf/util/bpf-event.h |  7 +++-
 tools/perf/util/env.c       | 88 +++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       | 19 ++++++++++
 tools/perf/util/session.c   |  1 +
 6 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index a11cb006f968..72df4b6fa36f 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -298,6 +298,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 		use_pager = 1;
 	commit_pager_choice();
 
+	perf_env__init(&perf_env);
 	perf_env__set_cmdline(&perf_env, argc, argv);
 	status = p->fn(argc, argv);
 	perf_config__exit();
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 5237e8f11997..37ee4e2a728a 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "machine.h"
+#include "env.h"
 #include "session.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
@@ -54,17 +55,28 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 	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)) {
@@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 						     machine, process);
 	}
 
-	/* Synthesize PERF_RECORD_BPF_EVENT */
 	if (!opts->no_bpf_event) {
+		/* Synthesize PERF_RECORD_BPF_EVENT */
 		*bpf_event = (struct bpf_event){
 			.header = {
 				.type = PERF_RECORD_BPF_EVENT,
@@ -167,6 +179,22 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 		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) {
+			err = -1;
+			goto out;
+		}
+
+		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);
 	}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 6698683612a7..fad932f7404f 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,14 +3,19 @@
 #define __PERF_BPF_EVENT_H
 
 #include <linux/compiler.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);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..98cd36f0e317 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,15 +3,97 @@
 #include "env.h"
 #include "sane_ctype.h"
 #include "util.h"
+#include "bpf-event.h"
 #include <errno.h>
 #include <sys/utsname.h>
+#include <bpf/libbpf.h>
 
 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_progs.lock);
+	p = &env->bpf_progs.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);
+			goto out;
+		}
+	}
+
+	rb_link_node(&info_node->rb_node, parent, p);
+	rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
+	env->bpf_progs.infos_cnt++;
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
+/* purge data in bpf_progs.infos tree */
+static void perf_env__purge_bpf(struct perf_env *env)
+{
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_write(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		rb_erase(&node->rb_node, root);
+		free(node);
+	}
+
+	env->bpf_progs.infos_cnt = 0;
+
+	up_write(&env->bpf_progs.lock);
+}
+
 void perf_env__exit(struct perf_env *env)
 {
 	int i;
 
+	perf_env__purge_bpf(env);
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -38,6 +120,12 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->memory_nodes);
 }
 
+void perf_env__init(struct perf_env *env)
+{
+	env->bpf_progs.infos = RB_ROOT;
+	init_rwsem(&env->bpf_progs.lock);
+}
+
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
 {
 	int i;
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..24b11c564ba4 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,9 @@
 #define __PERF_ENV_H
 
 #include <linux/types.h>
+#include <linux/rbtree.h>
 #include "cpumap.h"
+#include "rwsem.h"
 
 struct cpu_topology_map {
 	int	socket_id;
@@ -64,8 +66,20 @@ 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 {
+		struct rw_semaphore	lock;
+		struct rb_root		infos;
+		u32			infos_cnt;
+	} bpf_progs;
 };
 
+struct bpf_prog_info_node;
+
 extern struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env);
@@ -80,4 +94,9 @@ 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__init(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 */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0ec34227bd60..b17f1c9bc965 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -132,6 +132,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
 	ordered_events__init(&session->ordered_events,
 			     ordered_events__deliver_event, NULL);
 
+	perf_env__init(&session->header.env);
 	if (data) {
 		if (perf_data__open(data))
 			goto out_delete;

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Save bpf_prog_info information as headers to perf.data
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
  2019-03-12 13:10   ` Jiri Olsa
  2019-03-13 19:05   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:39   ` tip-bot for Song Liu
  2 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:39 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: sdf, mingo, jolsa, peterz, tglx, songliubraving, daniel, ast,
	namhyung, acme, linux-kernel, hpa

Commit-ID:  606f972b1361f477cbd4e6e8ac00742fde4b39db
Gitweb:     https://git.kernel.org/tip/606f972b1361f477cbd4e6e8ac00742fde4b39db
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:43 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:06 -0300

perf bpf: Save bpf_prog_info information as headers to perf.data

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.

Committer testing:

As root, being on the kernel sources top level directory, run:

  # perf trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c -e *msg

Just to compile and load a BPF program that attaches to the
raw_syscalls:sys_{enter,exit} tracepoints to trace the syscalls ending
in "msg" (recvmsg, sendmsg, recvmmsg, sendmmsg, etc).

Then do a systemwide perf record session for a few seconds:

  # perf record -a sleep 2s

Then look at:

  # perf report --header-only | grep -i bpf
  # bpf_prog_info of id 13
  # bpf_prog_info of id 14
  # bpf_prog_info of id 15
  # bpf_prog_info of id 16
  # bpf_prog_info of id 17
  # bpf_prog_info of id 18
  # bpf_prog_info of id 21
  # bpf_prog_info of id 22
  # bpf_prog_info of id 208
  # bpf_prog_info of id 209
  #

We need to show more info about these programs, like bpftool does for
the ones running on the system, i.e. 'perf record/perf report' become a
way of saving the BPF state in a machine to then analyse on another,
together with all the other information that is already saved in the
perf.data header:

  # perf report --header-only
  # ========
  # captured on    : Tue Mar 12 11:42:13 2019
  # header version : 1
  # data offset    : 296
  # data size      : 16294184
  # feat offset    : 16294480
  # hostname : quaco
  # os release : 5.0.0+
  # perf version : 5.0.gd783c8
  # arch : x86_64
  # nrcpus online : 8
  # nrcpus avail : 8
  # cpudesc : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
  # cpuid : GenuineIntel,6,142,10
  # total memory : 24555720 kB
  # cmdline : /home/acme/bin/perf (deleted) record -a
  # event : name = cycles:ppp, , id = { 3190123, 3190124, 3190125, 3190126, 3190127, 3190128, 3190129, 3190130 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1
  # CPU_TOPOLOGY info available, use -I to display
  # NUMA_TOPOLOGY info available, use -I to display
  # pmu mappings: intel_pt = 8, software = 1, power = 11, uprobe = 7, uncore_imc = 12, cpu = 4, cstate_core = 18, uncore_cbox_2 = 15, breakpoint = 5, uncore_cbox_0 = 13, tracepoint = 2, cstate_pkg = 19, uncore_arb = 17, kprobe = 6, i915 = 10, msr = 9, uncore_cbox_3 = 16, uncore_cbox_1 = 14
  # CACHE info available, use -I to display
  # time of first sample : 116392.441701
  # time of last sample : 116400.932584
  # sample duration :   8490.883 ms
  # MEM_TOPOLOGY info available, use -I to display
  # bpf_prog_info of id 13
  # bpf_prog_info of id 14
  # bpf_prog_info of id 15
  # bpf_prog_info of id 16
  # bpf_prog_info of id 17
  # bpf_prog_info of id 18
  # bpf_prog_info of id 21
  # bpf_prog_info of id 22
  # bpf_prog_info of id 208
  # bpf_prog_info of id 209
  # missing features: TRACING_DATA BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT
  # ========
  #

Committer notes:

We can't use the libbpf unconditionally, as the build may have been with
NO_LIBBPF, when we end up with linking errors, so provide dummy
{process,write}_bpf_prog_info() wrapped by HAVE_LIBBPF_SUPPORT for that
case.

Printing are not affected by this, so can continue as is.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-8-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/header.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.h |   1 +
 2 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b0683bf4d9f3..e6a81af516f6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -18,6 +18,7 @@
 #include <sys/utsname.h>
 #include <linux/time64.h>
 #include <dirent.h>
+#include <bpf/libbpf.h>
 
 #include "evlist.h"
 #include "evsel.h"
@@ -40,6 +41,7 @@
 #include "time-utils.h"
 #include "units.h"
 #include "cputopo.h"
+#include "bpf-event.h"
 
 #include "sane_ctype.h"
 
@@ -876,6 +878,56 @@ static int write_dir_format(struct feat_fd *ff,
 	return do_write(ff, &data->dir.version, sizeof(data->dir.version));
 }
 
+#ifdef HAVE_LIBBPF_SUPPORT
+static int write_bpf_prog_info(struct feat_fd *ff,
+			       struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_env *env = &ff->ph->env;
+	struct rb_root *root;
+	struct rb_node *next;
+	int ret;
+
+	down_read(&env->bpf_progs.lock);
+
+	ret = do_write(ff, &env->bpf_progs.infos_cnt,
+		       sizeof(env->bpf_progs.infos_cnt));
+	if (ret < 0)
+		goto out;
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+	while (next) {
+		struct bpf_prog_info_node *node;
+		size_t len;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		len = sizeof(struct bpf_prog_info_linear) +
+			node->info_linear->data_len;
+
+		/* before writing to file, translate address to offset */
+		bpf_program__bpil_addr_to_offs(node->info_linear);
+		ret = do_write(ff, node->info_linear, len);
+		/*
+		 * translate back to address even when do_write() fails,
+		 * so that this function never changes the data.
+		 */
+		bpf_program__bpil_offs_to_addr(node->info_linear);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+#else // HAVE_LIBBPF_SUPPORT
+static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
+			       struct perf_evlist *evlist __maybe_unused)
+{
+	return 0;
+}
+#endif // HAVE_LIBBPF_SUPPORT
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1367,6 +1419,29 @@ static void print_dir_format(struct feat_fd *ff, FILE *fp)
 	fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
 }
 
+static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
+{
+	struct perf_env *env = &ff->ph->env;
+	struct rb_root *root;
+	struct rb_node *next;
+
+	down_read(&env->bpf_progs.lock);
+
+	root = &env->bpf_progs.infos;
+	next = rb_first(root);
+
+	while (next) {
+		struct bpf_prog_info_node *node;
+
+		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+		next = rb_next(&node->rb_node);
+		fprintf(fp, "# bpf_prog_info of id %u\n",
+			node->info_linear->info.id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2414,6 +2489,81 @@ static int process_dir_format(struct feat_fd *ff,
 	return do_read_u64(ff, &data->dir.version);
 }
 
+#ifdef HAVE_LIBBPF_SUPPORT
+static int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+	int err = -1;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		u32 info_len, data_len;
+
+		info_linear = NULL;
+		info_node = NULL;
+		if (do_read_u32(ff, &info_len))
+			goto out;
+		if (do_read_u32(ff, &data_len))
+			goto out;
+
+		if (info_len > sizeof(struct bpf_prog_info)) {
+			pr_warning("detected invalid bpf_prog_info\n");
+			goto out;
+		}
+
+		info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
+				     data_len);
+		if (!info_linear)
+			goto out;
+		info_linear->info_len = sizeof(struct bpf_prog_info);
+		info_linear->data_len = data_len;
+		if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
+			goto out;
+		if (__do_read(ff, &info_linear->info, info_len))
+			goto out;
+		if (info_len < sizeof(struct bpf_prog_info))
+			memset(((void *)(&info_linear->info)) + info_len, 0,
+			       sizeof(struct bpf_prog_info) - info_len);
+
+		if (__do_read(ff, info_linear->data, data_len))
+			goto out;
+
+		info_node = malloc(sizeof(struct bpf_prog_info_node));
+		if (!info_node)
+			goto out;
+
+		/* after reading from file, translate offset to address */
+		bpf_program__bpil_offs_to_addr(info_linear);
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	}
+
+	return 0;
+out:
+	free(info_linear);
+	free(info_node);
+	up_write(&env->bpf_progs.lock);
+	return err;
+}
+#else // HAVE_LIBBPF_SUPPORT
+static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data __maybe_unused)
+{
+	return 0;
+}
+#endif // HAVE_LIBBPF_SUPPORT
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2474,7 +2624,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_OPN(DIR_FORMAT,	dir_format,	false)
+	FEAT_OPN(DIR_FORMAT,	dir_format,	false),
+	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false)
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 6a231340238d..1dc85f0f895d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -40,6 +40,7 @@ enum {
 	HEADER_MEM_TOPOLOGY,
 	HEADER_CLOCKID,
 	HEADER_DIR_FORMAT,
+	HEADER_BPF_PROG_INFO,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Save BTF in a rbtree in perf_env
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
  2019-03-12 15:00   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:39   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:39 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: songliubraving, namhyung, daniel, sdf, ast, hpa, mingo, tglx,
	acme, linux-kernel, peterz, jolsa

Commit-ID:  3792cb2ff43b1b193136a03ce1336462a827d792
Gitweb:     https://git.kernel.org/tip/3792cb2ff43b1b193136a03ce1336462a827d792
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:44 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf bpf: Save BTF in a rbtree in perf_env

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>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-9-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/bpf-event.c | 23 ++++++++++++++++
 tools/perf/util/bpf-event.h |  7 +++++
 tools/perf/util/env.c       | 67 +++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/env.h       |  5 ++++
 4 files changed, 102 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 37ee4e2a728a..a4fc52b4ffae 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -34,6 +34,28 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
 	return 0;
 }
 
+static int perf_env__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
@@ -113,6 +135,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
 			goto out;
 		}
 		has_btf = true;
+		perf_env__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 fad932f7404f..b9ec394dc7c7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -16,6 +16,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 98cd36f0e317..c6351b557bb0 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -64,6 +64,58 @@ 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_progs.lock);
+	p = &env->bpf_progs.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;
+		}
+	}
+
+	rb_link_node(&btf_node->rb_node, parent, p);
+	rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
+	env->bpf_progs.btfs_cnt++;
+out:
+	up_write(&env->bpf_progs.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_progs.lock);
+	n = env->bpf_progs.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_progs.lock);
+	return node;
+}
+
 /* purge data in bpf_progs.infos tree */
 static void perf_env__purge_bpf(struct perf_env *env)
 {
@@ -86,6 +138,20 @@ static void perf_env__purge_bpf(struct perf_env *env)
 
 	env->bpf_progs.infos_cnt = 0;
 
+	root = &env->bpf_progs.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(&node->rb_node, root);
+		free(node);
+	}
+
+	env->bpf_progs.btfs_cnt = 0;
+
 	up_write(&env->bpf_progs.lock);
 }
 
@@ -123,6 +189,7 @@ void perf_env__exit(struct perf_env *env)
 void perf_env__init(struct perf_env *env)
 {
 	env->bpf_progs.infos = RB_ROOT;
+	env->bpf_progs.btfs = RB_ROOT;
 	init_rwsem(&env->bpf_progs.lock);
 }
 
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 24b11c564ba4..4f8e2b485c01 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -75,10 +75,13 @@ struct perf_env {
 		struct rw_semaphore	lock;
 		struct rb_root		infos;
 		u32			infos_cnt;
+		struct rb_root		btfs;
+		u32			btfs_cnt;
 	} bpf_progs;
 };
 
 struct bpf_prog_info_node;
+struct btf_node;
 
 extern struct perf_env perf_env;
 
@@ -99,4 +102,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 */

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Save BTF information as headers to perf.data
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
  2019-03-12 15:14   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:40   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:40 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, namhyung, hpa, jolsa, ast, daniel, mingo, tglx,
	linux-kernel, peterz, songliubraving, sdf

Commit-ID:  a70a1123174ab592c5fa8ecf09f9fad9b335b872
Gitweb:     https://git.kernel.org/tip/a70a1123174ab592c5fa8ecf09f9fad9b335b872
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:45 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf bpf: Save BTF information as headers to perf.data

This patch enables 'perf record' to save BTF information as headers to
perf.data.

A new header type HEADER_BPF_BTF is introduced for this data.

Committer testing:

As root, being on the kernel sources top level directory, run:

    # perf trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c -e *msg

Just to compile and load a BPF program that attaches to the
raw_syscalls:sys_{enter,exit} tracepoints to trace the syscalls ending
in "msg" (recvmsg, sendmsg, recvmmsg, sendmmsg, etc).

Make sure you have a recent enough clang, say version 9, to get the
BTF ELF sections needed for this testing:

  # clang --version | head -1
  clang version 9.0.0 (https://git.llvm.org/git/clang.git/ 7906282d3afec5dfdc2b27943fd6c0309086c507) (https://git.llvm.org/git/llvm.git/ a1b5de1ff8ae8bc79dc8e86e1f82565229bd0500)
  # readelf -SW tools/perf/examples/bpf/augmented_raw_syscalls.o | grep BTF
    [22] .BTF              PROGBITS        0000000000000000 000ede 000b0e 00      0   0  1
    [23] .BTF.ext          PROGBITS        0000000000000000 0019ec 0002a0 00      0   0  1
    [24] .rel.BTF.ext      REL             0000000000000000 002fa8 000270 10     30  23  8

Then do a systemwide perf record session for a few seconds:

  # perf record -a sleep 2s

Then look at:

  # perf report --header-only | grep b[pt]f
  # event : name = cycles:ppp, , id = { 1116204, 1116205, 1116206, 1116207, 1116208, 1116209, 1116210, 1116211 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1
  # bpf_prog_info of id 13
  # bpf_prog_info of id 14
  # bpf_prog_info of id 15
  # bpf_prog_info of id 16
  # bpf_prog_info of id 17
  # bpf_prog_info of id 18
  # bpf_prog_info of id 21
  # bpf_prog_info of id 22
  # bpf_prog_info of id 51
  # bpf_prog_info of id 52
  # btf info of id 8
  #

We need to show more info about these BPF and BTF entries , but that can
be done later.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-10-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/header.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/header.h |   1 +
 2 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e6a81af516f6..01dda2f65d36 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -928,6 +928,39 @@ static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
 }
 #endif // HAVE_LIBBPF_SUPPORT
 
+static int write_bpf_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;
+	int ret;
+
+	down_read(&env->bpf_progs.lock);
+
+	ret = do_write(ff, &env->bpf_progs.btfs_cnt,
+		       sizeof(env->bpf_progs.btfs_cnt));
+
+	if (ret < 0)
+		goto out;
+
+	root = &env->bpf_progs.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);
+		ret = do_write(ff, &node->id,
+			       sizeof(u32) * 2 + node->data_size);
+		if (ret < 0)
+			goto out;
+	}
+out:
+	up_read(&env->bpf_progs.lock);
+	return ret;
+}
+
 static int cpu_cache_level__sort(const void *a, const void *b)
 {
 	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1442,6 +1475,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
 	up_read(&env->bpf_progs.lock);
 }
 
+static void print_bpf_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_progs.lock);
+
+	root = &env->bpf_progs.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, "# btf info of id %u\n", node->id);
+	}
+
+	up_read(&env->bpf_progs.lock);
+}
+
 static void free_event_desc(struct perf_evsel *events)
 {
 	struct perf_evsel *evsel;
@@ -2564,6 +2619,49 @@ static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data _
 }
 #endif // HAVE_LIBBPF_SUPPORT
 
+static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
+{
+	struct perf_env *env = &ff->ph->env;
+	u32 count, i;
+
+	if (ff->ph->needs_swap) {
+		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
+		return 0;
+	}
+
+	if (do_read_u32(ff, &count))
+		return -1;
+
+	down_write(&env->bpf_progs.lock);
+
+	for (i = 0; i < count; ++i) {
+		struct btf_node *node;
+		u32 id, data_size;
+
+		if (do_read_u32(ff, &id))
+			return -1;
+		if (do_read_u32(ff, &data_size))
+			return -1;
+
+		node = malloc(sizeof(struct btf_node) + data_size);
+		if (!node)
+			return -1;
+
+		node->id = id;
+		node->data_size = data_size;
+
+		if (__do_read(ff, node->data, data_size)) {
+			free(node);
+			return -1;
+		}
+
+		perf_env__insert_btf(env, node);
+	}
+
+	up_write(&env->bpf_progs.lock);
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
 	void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2625,7 +2723,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
 	FEAT_OPR(CLOCKID,	clockid,	false),
 	FEAT_OPN(DIR_FORMAT,	dir_format,	false),
-	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false)
+	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false),
+	FEAT_OPR(BPF_BTF,       bpf_btf,        false),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 1dc85f0f895d..386da49e1bfa 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -41,6 +41,7 @@ enum {
 	HEADER_CLOCKID,
 	HEADER_DIR_FORMAT,
 	HEADER_BPF_PROG_INFO,
+	HEADER_BPF_BTF,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf top: Add option --no-bpf-event
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
@ 2019-03-22 22:41   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:41 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: songliubraving, jolsa, tglx, hpa, peterz, namhyung, mingo, ast,
	sdf, linux-kernel, daniel, acme

Commit-ID:  ee7a112fbcc8edb4cf2f84ce5fcc2da7818fd4b8
Gitweb:     https://git.kernel.org/tip/ee7a112fbcc8edb4cf2f84ce5fcc2da7818fd4b8
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:46 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf top: Add option --no-bpf-event

This patch adds option --no-bpf-event to 'perf top', which is the same
as the option of 'perf record'.

The following patches will use this option.

Committer testing:

  # perf top -vv 2> /tmp/perf_event_attr.out
  # cat  /tmp/perf_event_attr.out
  ------------------------------------------------------------
  perf_event_attr:
    size                             112
    { sample_period, sample_freq }   4000
    sample_type                      IP|TID|TIME|CPU|PERIOD
    read_format                      ID
    disabled                         1
    inherit                          1
    mmap                             1
    comm                             1
    freq                             1
    task                             1
    precise_ip                       3
    sample_id_all                    1
    exclude_guest                    1
    mmap2                            1
    comm_exec                        1
    ksymbol                          1
    bpf_event                        1
  ------------------------------------------------------------
  #

After this patch:

  # perf top --no-bpf-event -vv 2> /tmp/perf_event_attr.out
  # cat  /tmp/perf_event_attr.out
  ------------------------------------------------------------
  perf_event_attr:
    size                             112
    { sample_period, sample_freq }   4000
    sample_type                      IP|TID|TIME|CPU|PERIOD
    read_format                      ID
    disabled                         1
    inherit                          1
    mmap                             1
    comm                             1
    freq                             1
    task                             1
    precise_ip                       3
    sample_id_all                    1
    exclude_guest                    1
    mmap2                            1
    comm_exec                        1
    ksymbol                          1
  ------------------------------------------------------------
  #

Signed-off-by: Song Liu <songliubraving@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-11-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.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 77e6190211d2..c2ea22c4ea67 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1469,6 +1469,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, "no-bpf-event", &top.record_opts.no_bpf_event, "do not 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",

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf feature detection: Add -lopcodes to feature-libbfd
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
@ 2019-03-22 22:41   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:41 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: ast, daniel, songliubraving, peterz, tglx, namhyung,
	linux-kernel, sdf, hpa, acme, jolsa, mingo

Commit-ID:  31be9478ed7f43d6351e0d5a2257ca76609c83d3
Gitweb:     https://git.kernel.org/tip/31be9478ed7f43d6351e0d5a2257ca76609c83d3
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:47 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf feature detection: Add -lopcodes to feature-libbfd

Both libbfd and libopcodes are distributed with binutil-dev/devel. When
libbfd is present, it is OK to assume that libopcodes also present. This
has been a safe assumption for bpftool.

This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
used in the next commit for BPF annotation.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-12-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Makefile.config | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 0f11d5891301..df4ad45599ca 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -713,7 +713,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lopcodes
 else
   # we are on a system that requires -liberty and (maybe) -lz
   # to link against -lbfd; test each case individually here
@@ -724,10 +724,10 @@ else
   $(call feature_check,libbfd-liberty-z)
 
   ifeq ($(feature-libbfd-liberty), 1)
-    EXTLIBS += -lbfd -liberty
+    EXTLIBS += -lbfd -lopcodes -liberty
   else
     ifeq ($(feature-libbfd-liberty-z), 1)
-      EXTLIBS += -lbfd -liberty -lz
+      EXTLIBS += -lbfd -lopcodes -liberty -lz
     endif
   endif
 endif

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
  2019-03-18 16:38   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:42   ` tip-bot for Song Liu
  2019-03-22 22:43   ` [tip:perf/urgent] perf build: Check what binutils's 'disassembler()' signature to use tip-bot for Song Liu
  2019-03-22 22:44   ` [tip:perf/urgent] perf annotate: Enable annotation of BPF programs tip-bot for Song Liu
  3 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:42 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: namhyung, ast, tglx, peterz, hpa, daniel, acme, jolsa, mingo,
	linux-kernel, sdf, songliubraving

Commit-ID:  9b86d04d53b98399017fea44e9047165ffe12d42
Gitweb:     https://git.kernel.org/tip/9b86d04d53b98399017fea44e9047165ffe12d42
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:48 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO

Introduce a new dso type DSO_BINARY_TYPE__BPF_PROG_INFO for BPF programs. In
symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso will call into a new
function symbol__disassemble_bpf() in an upcoming patch, where annotation line
information is filled based bpf_prog_info and btf saved in given perf_env.

Committer notes:

Removed the unnamed union with 'bpf_prog' and 'cache' in 'struct dso',
to fix this bug when exiting 'perf top':

  # perf top
  perf: Segmentation fault
  -------- backtrace --------
  perf[0x5a785a]
  /lib64/libc.so.6(+0x385bf)[0x7fd68443c5bf]
  perf(rb_first+0x2b)[0x4d6eeb]
  perf(dso__delete+0xb7)[0x4dffb7]
  perf[0x4f9e37]
  perf(perf_session__delete+0x64)[0x504df4]
  perf(cmd_top+0x1957)[0x454467]
  perf[0x4aad18]
  perf(main+0x61c)[0x42ec7c]
  /lib64/libc.so.6(__libc_start_main+0xf2)[0x7fd684428412]
  perf(_start+0x2d)[0x42eead]
  #
  # addr2line -fe ~/bin/perf 0x4dffb7
  dso_cache__free
  /home/acme/git/perf/tools/perf/util/dso.c:713

That is trying to access the dso->data.cache, and that is not used with
BPF programs, so we end up accessing what is in bpf_prog.first_member,
b00m.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
[ split from a larger patch ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/dso.c    | 1 +
 tools/perf/util/dso.h    | 8 ++++++++
 tools/perf/util/symbol.c | 1 +
 3 files changed, 10 insertions(+)

diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index ab8a455d2283..e059976d9d93 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 	case DSO_BINARY_TYPE__KALLSYMS:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
 	case DSO_BINARY_TYPE__JAVA_JIT:
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
 		break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index bb417c54c25a..6e3f63781e51 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,7 @@
 
 struct machine;
 struct map;
+struct perf_env;
 
 enum dso_binary_type {
 	DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -35,6 +36,7 @@ enum dso_binary_type {
 	DSO_BINARY_TYPE__KCORE,
 	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BPF_PROG_INFO,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
@@ -189,6 +191,12 @@ struct dso {
 		u64		 debug_frame_offset;
 		u64		 eh_frame_hdr_offset;
 	} data;
+	/* bpf prog information */
+	struct {
+		u32		id;
+		u32		sub_id;
+		struct perf_env	*env;
+	} bpf_prog;
 
 	union { /* Tool specific area */
 		void	 *priv;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 58442ca5e3c4..5cbad55cd99d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1455,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
 		return true;
 
+	case DSO_BINARY_TYPE__BPF_PROG_INFO:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 	default:
 		return false;

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf bpf: Process PERF_BPF_EVENT_PROG_LOAD for annotation
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
@ 2019-03-22 22:43   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:43 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: hpa, peterz, jolsa, daniel, linux-kernel, acme, namhyung, tglx,
	ast, sdf, mingo, songliubraving

Commit-ID:  3ca3877a9732b68cf0289367a859f6c163a79bfa
Gitweb:     https://git.kernel.org/tip/3ca3877a9732b68cf0289367a859f6c163a79bfa
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:49 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 19 Mar 2019 16:52:07 -0300

perf bpf: Process PERF_BPF_EVENT_PROG_LOAD for annotation

This patch adds processing of PERF_BPF_EVENT_PROG_LOAD, which sets
proper DSO type/id/etc of memory regions mapped to BPF programs to
DSO_BINARY_TYPE__BPF_PROG_INFO.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: kernel-team@fb.com
Link: http://lkml.kernel.org/r/20190312053051.2690567-14-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/bpf-event.c | 54 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index a4fc52b4ffae..852e960692cb 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -12,6 +12,7 @@
 #include "machine.h"
 #include "env.h"
 #include "session.h"
+#include "map.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -25,12 +26,65 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
 	return ret;
 }
 
+static int machine__process_bpf_event_load(struct machine *machine,
+					   union perf_event *event,
+					   struct perf_sample *sample __maybe_unused)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct perf_env *env = machine->env;
+	int id = event->bpf_event.id;
+	unsigned int i;
+
+	/* perf-record, no need to handle bpf-event */
+	if (env == NULL)
+		return 0;
+
+	info_node = perf_env__find_bpf_prog_info(env, id);
+	if (!info_node)
+		return 0;
+	info_linear = info_node->info_linear;
+
+	for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
+		u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
+		u64 addr = addrs[i];
+		struct map *map;
+
+		map = map_groups__find(&machine->kmaps, addr);
+
+		if (map) {
+			map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
+			map->dso->bpf_prog.id = id;
+			map->dso->bpf_prog.sub_id = i;
+			map->dso->bpf_prog.env = env;
+		}
+	}
+	return 0;
+}
+
 int machine__process_bpf_event(struct machine *machine __maybe_unused,
 			       union perf_event *event,
 			       struct perf_sample *sample __maybe_unused)
 {
 	if (dump_trace)
 		perf_event__fprintf_bpf_event(event, stdout);
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		return machine__process_bpf_event_load(machine, event, sample);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf build: Check what binutils's 'disassembler()' signature to use
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
  2019-03-18 16:38   ` Arnaldo Carvalho de Melo
  2019-03-22 22:42   ` [tip:perf/urgent] perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO tip-bot for Song Liu
@ 2019-03-22 22:43   ` tip-bot for Song Liu
  2019-03-22 22:44   ` [tip:perf/urgent] perf annotate: Enable annotation of BPF programs tip-bot for Song Liu
  3 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:43 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: guro, namhyung, tglx, jolsa, peterz, linux-kernel,
	jakub.kicinski, daniel, acme, sdf, ast, songliubraving, mingo,
	hpa

Commit-ID:  8a1b1718214cfd945fef14b3031e4e7262882a86
Gitweb:     https://git.kernel.org/tip/8a1b1718214cfd945fef14b3031e4e7262882a86
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:48 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 20 Mar 2019 16:42:10 -0300

perf build: Check what binutils's 'disassembler()' signature to use

Commit 003ca0fd2286 ("Refactor disassembler selection") in the binutils
repo, which changed the disassembler() function signature, so we must
use the feature test introduced in fb982666e380 ("tools/bpftool: fix
bpftool build with bintutils >= 2.9") to deal with that.

Committer testing:

After adding the missing function call to test-all.c, and:

  FEATURE_CHECK_LDFLAGS-disassembler-four-args = -bfd -lopcodes

And the fallbacks for cases where we need -liberty and sometimes -lz to
tools/perf/Makefile.config, we get:

  $ make -C tools/perf O=/tmp/build/perf install-bin
  make: Entering directory '/home/acme/git/perf/tools/perf'
    BUILD:   Doing 'make -j8' parallel build

  Auto-detecting system features:
  ...                         dwarf: [ on  ]
  ...            dwarf_getlocations: [ on  ]
  ...                         glibc: [ on  ]
  ...                          gtk2: [ on  ]
  ...                      libaudit: [ on  ]
  ...                        libbfd: [ on  ]
  ...                        libelf: [ on  ]
  ...                       libnuma: [ on  ]
  ...        numa_num_possible_cpus: [ on  ]
  ...                       libperl: [ on  ]
  ...                     libpython: [ on  ]
  ...                      libslang: [ on  ]
  ...                     libcrypto: [ on  ]
  ...                     libunwind: [ on  ]
  ...            libdw-dwarf-unwind: [ on  ]
  ...                          zlib: [ on  ]
  ...                          lzma: [ on  ]
  ...                     get_cpuid: [ on  ]
  ...                           bpf: [ on  ]
  ...                        libaio: [ on  ]
  ...        disassembler-four-args: [ on  ]
    CC       /tmp/build/perf/jvmti/libjvmti.o
    CC       /tmp/build/perf/builtin-bench.o
  <SNIP>
  $
  $

The feature detection test-all.bin gets successfully built and linked:

  $ ls -la /tmp/build/perf/feature/test-all.bin
  -rwxrwxr-x. 1 acme acme 2680352 Mar 19 11:07 /tmp/build/perf/feature/test-all.bin
  $ nm /tmp/build/perf/feature/test-all.bin  | grep -w disassembler
  0000000000061f90 T disassembler
  $

Time to move on to the patches that make use of this disassembler()
routine in binutils's libopcodes.

Signed-off-by: Song Liu <songliubraving@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <guro@fb.com>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
[ split from a larger patch, added missing FEATURE_CHECK_LDFLAGS-disassembler-four-args ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/build/Makefile.feature   | 6 ++++--
 tools/build/feature/test-all.c | 5 +++++
 tools/perf/Makefile.config     | 9 +++++++++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 61e46d54a67c..8d3864b061f3 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -66,7 +66,8 @@ FEATURE_TESTS_BASIC :=                  \
         sched_getcpu			\
         sdt				\
         setns				\
-        libaio
+        libaio				\
+        disassembler-four-args
 
 # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
 # of all feature tests
@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?=              \
          lzma                   \
          get_cpuid              \
          bpf			\
-         libaio
+         libaio			\
+         disassembler-four-args
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index e903b86b742f..7853e6d91090 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -178,6 +178,10 @@
 # include "test-reallocarray.c"
 #undef main
 
+#define main main_test_disassembler_four_args
+# include "test-disassembler-four-args.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -219,6 +223,7 @@ int main(int argc, char *argv[])
 	main_test_setns();
 	main_test_libaio();
 	main_test_reallocarray();
+	main_test_disassembler_four_args();
 
 	return 0;
 }
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index df4ad45599ca..fe3f97e342fa 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -227,6 +227,8 @@ FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
 
 FEATURE_CHECK_LDFLAGS-libaio = -lrt
 
+FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes
+
 CFLAGS += -fno-omit-frame-pointer
 CFLAGS += -ggdb3
 CFLAGS += -funwind-tables
@@ -725,11 +727,14 @@ else
 
   ifeq ($(feature-libbfd-liberty), 1)
     EXTLIBS += -lbfd -lopcodes -liberty
+    FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -ldl
   else
     ifeq ($(feature-libbfd-liberty-z), 1)
       EXTLIBS += -lbfd -lopcodes -liberty -lz
+      FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -lz -ldl
     endif
   endif
+  $(call feature_check,disassembler-four-args)
 endif
 
 ifdef NO_DEMANGLE
@@ -808,6 +813,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq ($(feature-disassembler-four-args), 1)
+    CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
+endif
+
 ifeq (${IS_64_BIT}, 1)
   ifndef NO_PERF_READ_VDSO32
     $(call feature_check,compile-32)

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf annotate: Enable annotation of BPF programs
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
                     ` (2 preceding siblings ...)
  2019-03-22 22:43   ` [tip:perf/urgent] perf build: Check what binutils's 'disassembler()' signature to use tip-bot for Song Liu
@ 2019-03-22 22:44   ` tip-bot for Song Liu
  3 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:44 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: daniel, sdf, peterz, jolsa, linux-kernel, hpa, namhyung, acme,
	ast, songliubraving, tglx, mingo

Commit-ID:  6987561c9e86eace45f2dbb0c564964a63f4150a
Gitweb:     https://git.kernel.org/tip/6987561c9e86eace45f2dbb0c564964a63f4150a
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:48 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 20 Mar 2019 16:43:15 -0300

perf annotate: Enable annotation of BPF programs

In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso calls into
a new function symbol__disassemble_bpf(), where annotation line
information is filled based on the bpf_prog_info and btf data saved in
given perf_env.

symbol__disassemble_bpf() uses binutils's libopcodes to disassemble bpf
programs.

Committer testing:

After fixing this:

  -               u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
  +               u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms);

Detected when crossbuilding to a 32-bit arch.

And making all this dependent on HAVE_LIBBFD_SUPPORT and
HAVE_LIBBPF_SUPPORT:

1) Have a BPF program running, one that has BTF info, etc, I used
   the tools/perf/examples/bpf/augmented_raw_syscalls.c put in place
   by 'perf trace'.

  # grep -B1 augmented_raw ~/.perfconfig
  [trace]
	add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c
  #
  # perf trace -e *mmsg
  dnf/6245 sendmmsg(20, 0x7f5485a88030, 2, MSG_NOSIGNAL) = 2
  NetworkManager/10055 sendmmsg(22<socket:[1056822]>, 0x7f8126ad1bb0, 2, MSG_NOSIGNAL) = 2

2) Then do a 'perf record' system wide for a while:

  # perf record -a
  ^C[ perf record: Woken up 68 times to write data ]
  [ perf record: Captured and wrote 19.427 MB perf.data (366891 samples) ]
  #

3) Check that we captured BPF and BTF info in the perf.data file:

  # perf report --header-only | grep 'b[pt]f'
  # event : name = cycles:ppp, , id = { 294789, 294790, 294791, 294792, 294793, 294794, 294795, 294796 }, size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|CPU|PERIOD, read_format = ID, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1
  # bpf_prog_info of id 13
  # bpf_prog_info of id 14
  # bpf_prog_info of id 15
  # bpf_prog_info of id 16
  # bpf_prog_info of id 17
  # bpf_prog_info of id 18
  # bpf_prog_info of id 21
  # bpf_prog_info of id 22
  # bpf_prog_info of id 41
  # bpf_prog_info of id 42
  # btf info of id 2
  #

4) Check which programs got recorded:

   # perf report | grep bpf_prog | head
     0.16%  exe              bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
     0.14%  exe              bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
     0.08%  fuse-overlayfs   bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
     0.07%  fuse-overlayfs   bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
     0.01%  clang-4.0        bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
     0.01%  clang-4.0        bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
     0.00%  clang            bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
     0.00%  runc             bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
     0.00%  clang            bpf_prog_819967866022f1e1_sys_enter      [k] bpf_prog_819967866022f1e1_sys_enter
     0.00%  sh               bpf_prog_c1bd85c092d6e4aa_sys_exit       [k] bpf_prog_c1bd85c092d6e4aa_sys_exit
  #

  This was with the default --sort order for 'perf report', which is:

    --sort comm,dso,symbol

  If we just look for the symbol, for instance:

   # perf report --sort symbol | grep bpf_prog | head
     0.26%  [k] bpf_prog_819967866022f1e1_sys_enter                -      -
     0.24%  [k] bpf_prog_c1bd85c092d6e4aa_sys_exit                 -      -
   #

  or the DSO:

   # perf report --sort dso | grep bpf_prog | head
     0.26%  bpf_prog_819967866022f1e1_sys_enter
     0.24%  bpf_prog_c1bd85c092d6e4aa_sys_exit
  #

We'll see the two BPF programs that augmented_raw_syscalls.o puts in
place,  one attached to the raw_syscalls:sys_enter and another to the
raw_syscalls:sys_exit tracepoints, as expected.

Now we can finally do, from the command line, annotation for one of
those two symbols, with the original BPF program source coude intermixed
with the disassembled JITed code:

  # perf annotate --stdio2 bpf_prog_819967866022f1e1_sys_enter

  Samples: 950  of event 'cycles:ppp', 4000 Hz, Event count (approx.): 553756947, [percent: local period]
  bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
  Percent      int sys_enter(struct syscall_enter_args *args)
   53.41         push   %rbp

    0.63         mov    %rsp,%rbp
    0.31         sub    $0x170,%rsp
    1.93         sub    $0x28,%rbp
    7.02         mov    %rbx,0x0(%rbp)
    3.20         mov    %r13,0x8(%rbp)
    1.07         mov    %r14,0x10(%rbp)
    0.61         mov    %r15,0x18(%rbp)
    0.11         xor    %eax,%eax
    1.29         mov    %rax,0x20(%rbp)
    0.11         mov    %rdi,%rbx
               	return bpf_get_current_pid_tgid();
    2.02       → callq  *ffffffffda6776d9
    2.76         mov    %eax,-0x148(%rbp)
                 mov    %rbp,%rsi
               int sys_enter(struct syscall_enter_args *args)
                 add    $0xfffffffffffffeb8,%rsi
               	return bpf_map_lookup_elem(pids, &pid) != NULL;
                 movabs $0xffff975ac2607800,%rdi

    1.26       → callq  *ffffffffda6789e9
                 cmp    $0x0,%rax
    2.43       → je     0
                 add    $0x38,%rax
    0.21         xor    %r13d,%r13d
               	if (pid_filter__has(&pids_filtered, getpid()))
    0.81         cmp    $0x0,%rax
               → jne    0
                 mov    %rbp,%rdi
               	probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
    2.22         add    $0xfffffffffffffeb8,%rdi
    0.11         mov    $0x40,%esi
    0.32         mov    %rbx,%rdx
    2.74       → callq  *ffffffffda658409
               	syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
    0.22         mov    %rbp,%rsi
    1.69         add    $0xfffffffffffffec0,%rsi
               	syscall = bpf_map_lookup_elem(&syscalls, &augmented_args.args.syscall_nr);
                 movabs $0xffff975bfcd36000,%rdi

                 add    $0xd0,%rdi
    0.21         mov    0x0(%rsi),%eax
    0.93         cmp    $0x200,%rax
               → jae    0
    0.10         shl    $0x3,%rax

    0.11         add    %rdi,%rax
    0.11       → jmp    0
                 xor    %eax,%eax
               	if (syscall == NULL || !syscall->enabled)
    1.07         cmp    $0x0,%rax
               → je     0
               	if (syscall == NULL || !syscall->enabled)
    6.57         movzbq 0x0(%rax),%rdi

               	if (syscall == NULL || !syscall->enabled)
                 cmp    $0x0,%rdi
    0.95       → je     0
                 mov    $0x40,%r8d
               	switch (augmented_args.args.syscall_nr) {
                 mov    -0x140(%rbp),%rdi
               	switch (augmented_args.args.syscall_nr) {
                 cmp    $0x2,%rdi
               → je     0
                 cmp    $0x101,%rdi
               → je     0
                 cmp    $0x15,%rdi
               → jne    0
               	case SYS_OPEN:	 filename_arg = (const void *)args->args[0];
                 mov    0x10(%rbx),%rdx
               → jmp    0
               	case SYS_OPENAT: filename_arg = (const void *)args->args[1];
                 mov    0x18(%rbx),%rdx
               	if (filename_arg != NULL) {
                 cmp    $0x0,%rdx
               → je     0
                 xor    %edi,%edi
               		augmented_args.filename.reserved = 0;
                 mov    %edi,-0x104(%rbp)
               		augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                 mov    %rbp,%rdi
                 add    $0xffffffffffffff00,%rdi
               		augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                 mov    $0x100,%esi
               → callq  *ffffffffda658499
                 mov    $0x148,%r8d
               		augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                 mov    %eax,-0x108(%rbp)
               		augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
                 mov    %rax,%rdi
                 shl    $0x20,%rdi

                 shr    $0x20,%rdi

               		if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
                 cmp    $0xff,%rdi
               → ja     0
               			len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
                 add    $0x48,%rax
               			len &= sizeof(augmented_args.filename.value) - 1;
                 and    $0xff,%rax
                 mov    %rax,%r8
                 mov    %rbp,%rcx
               	return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
                 add    $0xfffffffffffffeb8,%rcx
                 mov    %rbx,%rdi
                 movabs $0xffff975fbd72d800,%rsi

                 mov    $0xffffffff,%edx
               → callq  *ffffffffda658ad9
                 mov    %rax,%r13
               }
                 mov    %r13,%rax
    0.72         mov    0x0(%rbp),%rbx
                 mov    0x8(%rbp),%r13
    1.16         mov    0x10(%rbp),%r14
    0.10         mov    0x18(%rbp),%r15
    0.42         add    $0x28,%rbp
    0.54         leaveq
    0.54       ← retq
  #

Please see 'man perf-config' to see how to control what should be seen,
via ~/.perfconfig [annotate] section, for instance, one can suppress the
source code and see just the disassembly, etc.

Alternatively, use the TUI bu just using 'perf annotate', press
'/bpf_prog' to see the bpf symbols, press enter and do the interactive
annotation, which allows for dumping to a file after selecting the
the various output tunables, for instance, the above without source code
intermixed, plus showing all the instruction offsets:

  # perf annotate bpf_prog_819967866022f1e1_sys_enter

Then press: 's' to hide the source code + 'O' twice to show all
instruction offsets, then 'P' to print to the
bpf_prog_819967866022f1e1_sys_enter.annotation file, which will have:

  # cat bpf_prog_819967866022f1e1_sys_enter.annotation
  bpf_prog_819967866022f1e1_sys_enter() bpf_prog_819967866022f1e1_sys_enter
  Event: cycles:ppp

   53.41    0:   push   %rbp

    0.63    1:   mov    %rsp,%rbp
    0.31    4:   sub    $0x170,%rsp
    1.93    b:   sub    $0x28,%rbp
    7.02    f:   mov    %rbx,0x0(%rbp)
    3.20   13:   mov    %r13,0x8(%rbp)
    1.07   17:   mov    %r14,0x10(%rbp)
    0.61   1b:   mov    %r15,0x18(%rbp)
    0.11   1f:   xor    %eax,%eax
    1.29   21:   mov    %rax,0x20(%rbp)
    0.11   25:   mov    %rdi,%rbx
    2.02   28: → callq  *ffffffffda6776d9
    2.76   2d:   mov    %eax,-0x148(%rbp)
           33:   mov    %rbp,%rsi
           36:   add    $0xfffffffffffffeb8,%rsi
           3d:   movabs $0xffff975ac2607800,%rdi

    1.26   47: → callq  *ffffffffda6789e9
           4c:   cmp    $0x0,%rax
    2.43   50: → je     0
           52:   add    $0x38,%rax
    0.21   56:   xor    %r13d,%r13d
    0.81   59:   cmp    $0x0,%rax
           5d: → jne    0
           63:   mov    %rbp,%rdi
    2.22   66:   add    $0xfffffffffffffeb8,%rdi
    0.11   6d:   mov    $0x40,%esi
    0.32   72:   mov    %rbx,%rdx
    2.74   75: → callq  *ffffffffda658409
    0.22   7a:   mov    %rbp,%rsi
    1.69   7d:   add    $0xfffffffffffffec0,%rsi
           84:   movabs $0xffff975bfcd36000,%rdi

           8e:   add    $0xd0,%rdi
    0.21   95:   mov    0x0(%rsi),%eax
    0.93   98:   cmp    $0x200,%rax
           9f: → jae    0
    0.10   a1:   shl    $0x3,%rax

    0.11   a5:   add    %rdi,%rax
    0.11   a8: → jmp    0
           aa:   xor    %eax,%eax
    1.07   ac:   cmp    $0x0,%rax
           b0: → je     0
    6.57   b6:   movzbq 0x0(%rax),%rdi

           bb:   cmp    $0x0,%rdi
    0.95   bf: → je     0
           c5:   mov    $0x40,%r8d
           cb:   mov    -0x140(%rbp),%rdi
           d2:   cmp    $0x2,%rdi
           d6: → je     0
           d8:   cmp    $0x101,%rdi
           df: → je     0
           e1:   cmp    $0x15,%rdi
           e5: → jne    0
           e7:   mov    0x10(%rbx),%rdx
           eb: → jmp    0
           ed:   mov    0x18(%rbx),%rdx
           f1:   cmp    $0x0,%rdx
           f5: → je     0
           f7:   xor    %edi,%edi
           f9:   mov    %edi,-0x104(%rbp)
           ff:   mov    %rbp,%rdi
          102:   add    $0xffffffffffffff00,%rdi
          109:   mov    $0x100,%esi
          10e: → callq  *ffffffffda658499
          113:   mov    $0x148,%r8d
          119:   mov    %eax,-0x108(%rbp)
          11f:   mov    %rax,%rdi
          122:   shl    $0x20,%rdi

          126:   shr    $0x20,%rdi

          12a:   cmp    $0xff,%rdi
          131: → ja     0
          133:   add    $0x48,%rax
          137:   and    $0xff,%rax
          13d:   mov    %rax,%r8
          140:   mov    %rbp,%rcx
          143:   add    $0xfffffffffffffeb8,%rcx
          14a:   mov    %rbx,%rdi
          14d:   movabs $0xffff975fbd72d800,%rsi

          157:   mov    $0xffffffff,%edx
          15c: → callq  *ffffffffda658ad9
          161:   mov    %rax,%r13
          164:   mov    %r13,%rax
    0.72  167:   mov    0x0(%rbp),%rbx
          16b:   mov    0x8(%rbp),%r13
    1.16  16f:   mov    0x10(%rbp),%r14
    0.10  173:   mov    0x18(%rbp),%r15
    0.42  177:   add    $0x28,%rbp
    0.54  17b:   leaveq
    0.54  17c: ← retq

Another cool way to test all this is to symple use 'perf top' look for
those symbols, go there and press enter, annotate it live :-)

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-13-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/annotate.c  | 163 +++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/annotate.h  |   1 +
 tools/perf/util/bpf-event.c |   2 +-
 3 files changed, 164 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 5f6dbbf5d749..c8b01176c9e1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -10,6 +10,10 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <libgen.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
 #include "util.h"
 #include "ui/ui.h"
 #include "sort.h"
@@ -24,6 +28,7 @@
 #include "annotate.h"
 #include "evsel.h"
 #include "evlist.h"
+#include "bpf-event.h"
 #include "block-range.h"
 #include "string2.h"
 #include "arch/common.h"
@@ -31,6 +36,7 @@
 #include <pthread.h>
 #include <linux/bitops.h>
 #include <linux/kernel.h>
+#include <bpf/libbpf.h>
 
 /* FIXME: For the HE_COLORSET */
 #include "ui/browser.h"
@@ -1615,6 +1621,9 @@ int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *
 			  "  --vmlinux vmlinux\n", build_id_msg ?: "");
 	}
 		break;
+	case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF:
+		scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation");
+		break;
 	default:
 		scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
 		break;
@@ -1674,6 +1683,156 @@ fallback:
 	return 0;
 }
 
+#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
+#define PACKAGE "perf"
+#include <bfd.h>
+#include <dis-asm.h>
+
+static int symbol__disassemble_bpf(struct symbol *sym,
+				   struct annotate_args *args)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct annotation_options *opts = args->options;
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_linfo *prog_linfo = NULL;
+	struct bpf_prog_info_node *info_node;
+	int len = sym->end - sym->start;
+	disassembler_ftype disassemble;
+	struct map *map = args->ms.map;
+	struct disassemble_info info;
+	struct dso *dso = map->dso;
+	int pc = 0, count, sub_id;
+	struct btf *btf = NULL;
+	char tpath[PATH_MAX];
+	size_t buf_size;
+	int nr_skip = 0;
+	int ret = -1;
+	char *buf;
+	bfd *bfdf;
+	FILE *s;
+
+	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
+		return -1;
+
+	pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
+		 sym->name, sym->start, sym->end - sym->start);
+
+	memset(tpath, 0, sizeof(tpath));
+	perf_exe(tpath, sizeof(tpath));
+
+	bfdf = bfd_openr(tpath, NULL);
+	assert(bfdf);
+	assert(bfd_check_format(bfdf, bfd_object));
+
+	s = open_memstream(&buf, &buf_size);
+	if (!s)
+		goto out;
+	init_disassemble_info(&info, s,
+			      (fprintf_ftype) fprintf);
+
+	info.arch = bfd_get_arch(bfdf);
+	info.mach = bfd_get_mach(bfdf);
+
+	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
+						 dso->bpf_prog.id);
+	if (!info_node)
+		goto out;
+	info_linear = info_node->info_linear;
+	sub_id = dso->bpf_prog.sub_id;
+
+	info.buffer = (void *)(info_linear->info.jited_prog_insns);
+	info.buffer_length = info_linear->info.jited_prog_len;
+
+	if (info_linear->info.nr_line_info)
+		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
+
+	if (info_linear->info.btf_id) {
+		struct btf_node *node;
+
+		node = perf_env__find_btf(dso->bpf_prog.env,
+					  info_linear->info.btf_id);
+		if (node)
+			btf = btf__new((__u8 *)(node->data),
+				       node->data_size);
+	}
+
+	disassemble_init_for_target(&info);
+
+#ifdef DISASM_FOUR_ARGS_SIGNATURE
+	disassemble = disassembler(info.arch,
+				   bfd_big_endian(bfdf),
+				   info.mach,
+				   bfdf);
+#else
+	disassemble = disassembler(bfdf);
+#endif
+	assert(disassemble);
+
+	fflush(s);
+	do {
+		const struct bpf_line_info *linfo = NULL;
+		struct disasm_line *dl;
+		size_t prev_buf_size;
+		const char *srcline;
+		u64 addr;
+
+		addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
+		count = disassemble(pc, &info);
+
+		if (prog_linfo)
+			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
+								addr, sub_id,
+								nr_skip);
+
+		if (linfo && btf) {
+			srcline = btf__name_by_offset(btf, linfo->line_off);
+			nr_skip++;
+		} else
+			srcline = NULL;
+
+		fprintf(s, "\n");
+		prev_buf_size = buf_size;
+		fflush(s);
+
+		if (!opts->hide_src_code && srcline) {
+			args->offset = -1;
+			args->line = strdup(srcline);
+			args->line_nr = 0;
+			args->ms.sym  = sym;
+			dl = disasm_line__new(args);
+			if (dl) {
+				annotation_line__add(&dl->al,
+						     &notes->src->source);
+			}
+		}
+
+		args->offset = pc;
+		args->line = buf + prev_buf_size;
+		args->line_nr = 0;
+		args->ms.sym  = sym;
+		dl = disasm_line__new(args);
+		if (dl)
+			annotation_line__add(&dl->al, &notes->src->source);
+
+		pc += count;
+	} while (count > 0 && pc < len);
+
+	ret = 0;
+out:
+	free(prog_linfo);
+	free(btf);
+	fclose(s);
+	bfd_close(bfdf);
+	return ret;
+}
+#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
+static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
+				   struct annotate_args *args __maybe_unused)
+{
+	return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
+}
+#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
+
 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 {
 	struct annotation_options *opts = args->options;
@@ -1701,7 +1860,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
 		 dso, dso->long_name, sym, sym->name);
 
-	if (dso__is_kcore(dso)) {
+	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+		return symbol__disassemble_bpf(sym, args);
+	} else if (dso__is_kcore(dso)) {
 		kce.kcore_filename = symfs_filename;
 		kce.addr = map__rip_2objdump(map, sym->start);
 		kce.offs = sym->start;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index df34fe483164..5bc0cf655d37 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -369,6 +369,7 @@ enum symbol_disassemble_errno {
 	__SYMBOL_ANNOTATE_ERRNO__START		= -10000,
 
 	SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX	= __SYMBOL_ANNOTATE_ERRNO__START,
+	SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF,
 
 	__SYMBOL_ANNOTATE_ERRNO__END,
 };
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 852e960692cb..7ffe7db59828 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -46,7 +46,7 @@ static int machine__process_bpf_event_load(struct machine *machine,
 	info_linear = info_node->info_linear;
 
 	for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
-		u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
+		u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms);
 		u64 addr = addrs[i];
 		struct map *map;
 

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf evlist: Introduce side band thread
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 14/15] perf: introduce side band thread Song Liu
@ 2019-03-22 22:45   ` tip-bot for Song Liu
  0 siblings, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:45 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: jolsa, sdf, hpa, acme, songliubraving, mingo, peterz,
	linux-kernel, daniel, ast, namhyung, tglx

Commit-ID:  657ee5531903339b06697581532ed32d4762526e
Gitweb:     https://git.kernel.org/tip/657ee5531903339b06697581532ed32d4762526e
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:50 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Mar 2019 11:27:03 -0300

perf evlist: Introduce side band thread

This patch introduces side band thread that captures extended
information for events like PERF_RECORD_BPF_EVENT.

This new thread uses its own evlist that uses ring buffer with very low
watermark for lower latency.

To use side band thread, we need to:

1. add side band event(s) by calling perf_evlist__add_sb_event();
2. calls perf_evlist__start_sb_thread();
3. at the end of perf run, perf_evlist__stop_sb_thread().

In the next patch, we use this thread to handle PERF_RECORD_BPF_EVENT.

Committer notes:

Add fix by Jiri Olsa for when te sb_tread can't get started and then at
the end the stop_sb_thread() segfaults when joining the (non-existing)
thread.

That can happen when running 'perf top' or 'perf record' as a normal
user, for instance.

Further checks need to be done on top of this to more graciously handle
these possible failure scenarios.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-15-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-record.c |   9 ++++
 tools/perf/builtin-top.c    |   9 ++++
 tools/perf/util/evlist.c    | 119 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h    |  12 +++++
 tools/perf/util/evsel.h     |   6 +++
 5 files changed, 155 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e79faccd7842..6f645fd72fed 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1137,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	struct perf_data *data = &rec->data;
 	struct perf_session *session;
 	bool disabled = false, draining = false;
+	struct perf_evlist *sb_evlist = NULL;
 	int fd;
 
 	atexit(record__sig_exit);
@@ -1237,6 +1238,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
+		pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
+		opts->no_bpf_event = true;
+	}
+
 	err = record__synthesize(rec, false);
 	if (err < 0)
 		goto out_child;
@@ -1487,6 +1493,9 @@ out_child:
 
 out_delete_session:
 	perf_session__delete(session);
+
+	if (!opts->no_bpf_event)
+		perf_evlist__stop_sb_thread(sb_evlist);
 	return status;
 }
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c2ea22c4ea67..3ce8a8db6c1d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1501,6 +1501,7 @@ int cmd_top(int argc, const char **argv)
 			"number of thread to run event synthesize"),
 	OPT_END()
 	};
+	struct perf_evlist *sb_evlist = NULL;
 	const char * const top_usage[] = {
 		"perf top [<options>]",
 		NULL
@@ -1636,8 +1637,16 @@ int cmd_top(int argc, const char **argv)
 		goto out_delete_evlist;
 	}
 
+	if (perf_evlist__start_sb_thread(sb_evlist, target)) {
+		pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
+		opts->no_bpf_event = true;
+	}
+
 	status = __cmd_top(&top);
 
+	if (!opts->no_bpf_event)
+		perf_evlist__stop_sb_thread(sb_evlist);
+
 out_delete_evlist:
 	perf_evlist__delete(top.evlist);
 	perf_session__delete(top.session);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ed20f4379956..ec78e93085de 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@
 #include "debug.h"
 #include "units.h"
 #include "asm/bug.h"
+#include "bpf-event.h"
 #include <signal.h>
 #include <unistd.h>
 
@@ -1856,3 +1857,121 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
 	}
 	return leader;
 }
+
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data)
+{
+	struct perf_evsel *evsel;
+	bool new_evlist = (*evlist) == NULL;
+
+	if (*evlist == NULL)
+		*evlist = perf_evlist__new();
+	if (*evlist == NULL)
+		return -1;
+
+	if (!attr->sample_id_all) {
+		pr_warning("enabling sample_id_all for all side band events\n");
+		attr->sample_id_all = 1;
+	}
+
+	evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries);
+	if (!evsel)
+		goto out_err;
+
+	evsel->side_band.cb = cb;
+	evsel->side_band.data = data;
+	perf_evlist__add(*evlist, evsel);
+	return 0;
+
+out_err:
+	if (new_evlist) {
+		perf_evlist__delete(*evlist);
+		*evlist = NULL;
+	}
+	return -1;
+}
+
+static void *perf_evlist__poll_thread(void *arg)
+{
+	struct perf_evlist *evlist = arg;
+	bool draining = false;
+	int i;
+
+	while (draining || !(evlist->thread.done)) {
+		if (draining)
+			draining = false;
+		else if (evlist->thread.done)
+			draining = true;
+
+		if (!draining)
+			perf_evlist__poll(evlist, 1000);
+
+		for (i = 0; i < evlist->nr_mmaps; i++) {
+			struct perf_mmap *map = &evlist->mmap[i];
+			union perf_event *event;
+
+			if (perf_mmap__read_init(map))
+				continue;
+			while ((event = perf_mmap__read_event(map)) != NULL) {
+				struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
+
+				if (evsel && evsel->side_band.cb)
+					evsel->side_band.cb(event, evsel->side_band.data);
+				else
+					pr_warning("cannot locate proper evsel for the side band event\n");
+
+				perf_mmap__consume(map);
+			}
+			perf_mmap__read_done(map);
+		}
+	}
+	return NULL;
+}
+
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target)
+{
+	struct perf_evsel *counter;
+
+	if (!evlist)
+		return 0;
+
+	if (perf_evlist__create_maps(evlist, target))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__open(counter, evlist->cpus,
+				     evlist->threads) < 0)
+			goto out_delete_evlist;
+	}
+
+	if (perf_evlist__mmap(evlist, UINT_MAX))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(evlist, counter) {
+		if (perf_evsel__enable(counter))
+			goto out_delete_evlist;
+	}
+
+	evlist->thread.done = 0;
+	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
+		goto out_delete_evlist;
+
+	return 0;
+
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	evlist = NULL;
+	return -1;
+}
+
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
+{
+	if (!evlist)
+		return;
+	evlist->thread.done = 1;
+	pthread_join(evlist->thread.th, NULL);
+	perf_evlist__delete(evlist);
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 744906dd4887..dcb68f34d2cd 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,10 @@ struct perf_evlist {
 				       struct perf_sample *sample);
 	u64		first_sample_time;
 	u64		last_sample_time;
+	struct {
+		pthread_t		th;
+		volatile int		done;
+	} thread;
 };
 
 struct perf_evsel_str_handler {
@@ -87,6 +91,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
 
 int perf_evlist__add_dummy(struct perf_evlist *evlist);
 
+int perf_evlist__add_sb_event(struct perf_evlist **evlist,
+			      struct perf_event_attr *attr,
+			      perf_evsel__sb_cb_t cb,
+			      void *data);
+int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
+				 struct target *target);
+void perf_evlist__stop_sb_thread(struct perf_evlist *evlist);
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
 			   const char *sys, const char *name, void *handler);
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index cc578e02e08f..0f2c6c93d721 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -73,6 +73,8 @@ struct perf_evsel_config_term {
 
 struct perf_stat_evsel;
 
+typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);
+
 /** struct perf_evsel - event selector
  *
  * @evlist - evlist this evsel is in, if it is in one.
@@ -151,6 +153,10 @@ struct perf_evsel {
 	bool			collect_stat;
 	bool			weak_group;
 	const char		*pmu_name;
+	struct {
+		perf_evsel__sb_cb_t	*cb;
+		void			*data;
+	} side_band;
 };
 
 union u64_swap {

^ permalink raw reply related	[flat|nested] 100+ messages in thread

* [tip:perf/urgent] perf tools: Save bpf_prog_info and BTF of new BPF programs
  2019-03-12  5:30 ` [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
  2019-03-19 15:25   ` Arnaldo Carvalho de Melo
@ 2019-03-22 22:45   ` tip-bot for Song Liu
  1 sibling, 0 replies; 100+ messages in thread
From: tip-bot for Song Liu @ 2019-03-22 22:45 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: daniel, acme, peterz, ast, tglx, jolsa, songliubraving, namhyung,
	hpa, linux-kernel, sdf, mingo

Commit-ID:  d56354dc49091e33d9ffca732ac913ed2df70537
Gitweb:     https://git.kernel.org/tip/d56354dc49091e33d9ffca732ac913ed2df70537
Author:     Song Liu <songliubraving@fb.com>
AuthorDate: Mon, 11 Mar 2019 22:30:51 -0700
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Mar 2019 11:27:04 -0300

perf tools: Save bpf_prog_info and BTF of new BPF programs

To fully annotate BPF programs with source code mapping, 4 different
information are needed:

    1) PERF_RECORD_KSYMBOL
    2) PERF_RECORD_BPF_EVENT
    3) bpf_prog_info
    4) btf

This patch handles 3) and 4) for BPF programs loaded after 'perf
record|top'.

For timely process of these information, a dedicated event is added to
the side band evlist.

When PERF_RECORD_BPF_EVENT is received via the side band event, the
polling thread gathers 3) and 4) vis sys_bpf and store them in perf_env.

This information is saved to perf.data at the end of 'perf record'.

Committer testing:

The 'wakeup_watermark' member in 'struct perf_event_attr' is inside a
unnamed union, so can't be used in a struct designated initialization
with older gccs, get it out of that, isolating as 'attr.wakeup_watermark
= 1;' to work with all gcc versions.

We also need to add '--no-bpf-event' to the 'perf record'
perf_event_attr tests in 'perf test', as the way that that test goes is
to intercept the events being setup and looking if they match the fields
described in the control files, since now it finds first the side band
event used to catch the PERF_RECORD_BPF_EVENT, they all fail.

With these issues fixed:

Same scenario as for testing BPF programs loaded before 'perf record' or
'perf top' starts, only start the BPF programs after 'perf record|top',
so that its information get collected by the sideband threads, the rest
works as for the programs loaded before start monitoring.

Add missing 'inline' to the bpf_event__add_sb_event() when
HAVE_LIBBPF_SUPPORT is not defined, fixing the build in systems without
binutils devel files installed.

Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-16-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-record.c                        |   3 +
 tools/perf/builtin-top.c                           |   3 +
 tools/perf/tests/attr/test-record-C0               |   2 +-
 tools/perf/tests/attr/test-record-basic            |   2 +-
 tools/perf/tests/attr/test-record-branch-any       |   2 +-
 .../perf/tests/attr/test-record-branch-filter-any  |   2 +-
 .../tests/attr/test-record-branch-filter-any_call  |   2 +-
 .../tests/attr/test-record-branch-filter-any_ret   |   2 +-
 tools/perf/tests/attr/test-record-branch-filter-hv |   2 +-
 .../tests/attr/test-record-branch-filter-ind_call  |   2 +-
 tools/perf/tests/attr/test-record-branch-filter-k  |   2 +-
 tools/perf/tests/attr/test-record-branch-filter-u  |   2 +-
 tools/perf/tests/attr/test-record-count            |   2 +-
 tools/perf/tests/attr/test-record-data             |   2 +-
 tools/perf/tests/attr/test-record-freq             |   2 +-
 tools/perf/tests/attr/test-record-graph-default    |   2 +-
 tools/perf/tests/attr/test-record-graph-dwarf      |   2 +-
 tools/perf/tests/attr/test-record-graph-fp         |   2 +-
 tools/perf/tests/attr/test-record-group            |   2 +-
 tools/perf/tests/attr/test-record-group-sampling   |   2 +-
 tools/perf/tests/attr/test-record-group1           |   2 +-
 tools/perf/tests/attr/test-record-no-buffering     |   2 +-
 tools/perf/tests/attr/test-record-no-inherit       |   2 +-
 tools/perf/tests/attr/test-record-no-samples       |   2 +-
 tools/perf/tests/attr/test-record-period           |   2 +-
 tools/perf/tests/attr/test-record-raw              |   2 +-
 tools/perf/util/bpf-event.c                        | 100 +++++++++++++++++++++
 tools/perf/util/bpf-event.h                        |  15 ++++
 28 files changed, 145 insertions(+), 24 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6f645fd72fed..4e2d953d4bc5 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1238,6 +1238,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	if (!opts->no_bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &session->header.env);
+
 	if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
 		pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
 		opts->no_bpf_event = true;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 3ce8a8db6c1d..1999d6533d12 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1637,6 +1637,9 @@ int cmd_top(int argc, const char **argv)
 		goto out_delete_evlist;
 	}
 
+	if (!top.record_opts.no_bpf_event)
+		bpf_event__add_sb_event(&sb_evlist, &perf_env);
+
 	if (perf_evlist__start_sb_thread(sb_evlist, target)) {
 		pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
 		opts->no_bpf_event = true;
diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0
index cb0a3138fa54..93818054ae20 100644
--- a/tools/perf/tests/attr/test-record-C0
+++ b/tools/perf/tests/attr/test-record-C0
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -C 0 kill >/dev/null 2>&1
+args    = --no-bpf-event -C 0 kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/attr/test-record-basic
index 85a23cf35ba1..b0ca42a5ecc9 100644
--- a/tools/perf/tests/attr/test-record-basic
+++ b/tools/perf/tests/attr/test-record-basic
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = kill >/dev/null 2>&1
+args    = --no-bpf-event kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/attr/test-record-branch-any
index 81f839e2fad0..1a99b3ce6b89 100644
--- a/tools/perf/tests/attr/test-record-branch-any
+++ b/tools/perf/tests/attr/test-record-branch-any
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -b kill >/dev/null 2>&1
+args    = --no-bpf-event -b kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/attr/test-record-branch-filter-any
index 357421f4dfce..709768b508c6 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-any
+++ b/tools/perf/tests/attr/test-record-branch-filter-any
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j any kill >/dev/null 2>&1
+args    = --no-bpf-event -j any kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/attr/test-record-branch-filter-any_call
index dbc55f2ab845..f943221f7825 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-any_call
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_call
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j any_call kill >/dev/null 2>&1
+args    = --no-bpf-event -j any_call kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/attr/test-record-branch-filter-any_ret
index a0824ff8e131..fd4f5b4154a9 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-any_ret
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_ret
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j any_ret kill >/dev/null 2>&1
+args    = --no-bpf-event -j any_ret kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/attr/test-record-branch-filter-hv
index f34d6f120181..4e52d685ebe1 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-hv
+++ b/tools/perf/tests/attr/test-record-branch-filter-hv
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j hv kill >/dev/null 2>&1
+args    = --no-bpf-event -j hv kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/attr/test-record-branch-filter-ind_call
index b86a35232248..e08c6ab3796e 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-ind_call
+++ b/tools/perf/tests/attr/test-record-branch-filter-ind_call
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j ind_call kill >/dev/null 2>&1
+args    = --no-bpf-event -j ind_call kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/attr/test-record-branch-filter-k
index d3fbc5e1858a..b4b98f84fc2f 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-k
+++ b/tools/perf/tests/attr/test-record-branch-filter-k
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j k kill >/dev/null 2>&1
+args    = --no-bpf-event -j k kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/attr/test-record-branch-filter-u
index a318f0dda173..fb9610edbb0d 100644
--- a/tools/perf/tests/attr/test-record-branch-filter-u
+++ b/tools/perf/tests/attr/test-record-branch-filter-u
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -j u kill >/dev/null 2>&1
+args    = --no-bpf-event -j u kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/attr/test-record-count
index 34f6cc577263..5e9b9019d786 100644
--- a/tools/perf/tests/attr/test-record-count
+++ b/tools/perf/tests/attr/test-record-count
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -c 123 kill >/dev/null 2>&1
+args    = --no-bpf-event -c 123 kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
index a9cf2233b0ce..a99bb13149c2 100644
--- a/tools/perf/tests/attr/test-record-data
+++ b/tools/perf/tests/attr/test-record-data
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -d kill >/dev/null 2>&1
+args    = --no-bpf-event -d kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/attr/test-record-freq
index bf4cb459f0d5..89e29f6b2ae0 100644
--- a/tools/perf/tests/attr/test-record-freq
+++ b/tools/perf/tests/attr/test-record-freq
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -F 100 kill >/dev/null 2>&1
+args    = --no-bpf-event -F 100 kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default
index 0b216e69760c..5d8234d50845 100644
--- a/tools/perf/tests/attr/test-record-graph-default
+++ b/tools/perf/tests/attr/test-record-graph-default
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -g kill >/dev/null 2>&1
+args    = --no-bpf-event -g kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
index da2fa73bd0a2..ae92061d611d 100644
--- a/tools/perf/tests/attr/test-record-graph-dwarf
+++ b/tools/perf/tests/attr/test-record-graph-dwarf
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = --call-graph dwarf -- kill >/dev/null 2>&1
+args    = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp
index 625d190bb798..5630521c0b0f 100644
--- a/tools/perf/tests/attr/test-record-graph-fp
+++ b/tools/perf/tests/attr/test-record-graph-fp
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = --call-graph fp kill >/dev/null 2>&1
+args    = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
index 618ba1c17474..14ee60fd3f41 100644
--- a/tools/perf/tests/attr/test-record-group
+++ b/tools/perf/tests/attr/test-record-group
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = --group -e cycles,instructions kill >/dev/null 2>&1
+args    = --no-bpf-event --group -e cycles,instructions kill >/dev/null 2>&1
 ret     = 1
 
 [event-1:base-record]
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
index f0729c454f16..300b9f7e6d69 100644
--- a/tools/perf/tests/attr/test-record-group-sampling
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
+args    = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
 ret     = 1
 
 [event-1:base-record]
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
index 48e8bd12fe46..3ffe246e0228 100644
--- a/tools/perf/tests/attr/test-record-group1
+++ b/tools/perf/tests/attr/test-record-group1
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -e '{cycles,instructions}' kill >/dev/null 2>&1
+args    = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1
 ret     = 1
 
 [event-1:base-record]
diff --git a/tools/perf/tests/attr/test-record-no-buffering b/tools/perf/tests/attr/test-record-no-buffering
index aa3956d8fe20..583dcbb078ba 100644
--- a/tools/perf/tests/attr/test-record-no-buffering
+++ b/tools/perf/tests/attr/test-record-no-buffering
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = --no-buffering kill >/dev/null 2>&1
+args    = --no-bpf-event --no-buffering kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
index 560943decb87..15d1dc162e1c 100644
--- a/tools/perf/tests/attr/test-record-no-inherit
+++ b/tools/perf/tests/attr/test-record-no-inherit
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -i kill >/dev/null 2>&1
+args    = --no-bpf-event -i kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/attr/test-record-no-samples
index 8eb73ab639e0..596fbd6d5a2c 100644
--- a/tools/perf/tests/attr/test-record-no-samples
+++ b/tools/perf/tests/attr/test-record-no-samples
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -n kill >/dev/null 2>&1
+args    = --no-bpf-event -n kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/attr/test-record-period
index 69bc748f0f27..119101154c5e 100644
--- a/tools/perf/tests/attr/test-record-period
+++ b/tools/perf/tests/attr/test-record-period
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -c 100 -P kill >/dev/null 2>&1
+args    = --no-bpf-event -c 100 -P kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/attr/test-record-raw
index a188a614a44c..13a5f7860c78 100644
--- a/tools/perf/tests/attr/test-record-raw
+++ b/tools/perf/tests/attr/test-record-raw
@@ -1,6 +1,6 @@
 [config]
 command = record
-args    = -R kill >/dev/null 2>&1
+args    = --no-bpf-event -R kill >/dev/null 2>&1
 ret     = 1
 
 [event:base-record]
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 7ffe7db59828..2a8c245ca942 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -13,6 +13,7 @@
 #include "env.h"
 #include "session.h"
 #include "map.h"
+#include "evlist.h"
 
 #define ptr_to_u64(ptr)    ((__u64)(unsigned long)(ptr))
 
@@ -330,3 +331,102 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 	free(event);
 	return err;
 }
+
+static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
+{
+	struct bpf_prog_info_linear *info_linear;
+	struct bpf_prog_info_node *info_node;
+	struct btf *btf = NULL;
+	u64 arrays;
+	u32 btf_id;
+	int fd;
+
+	fd = bpf_prog_get_fd_by_id(id);
+	if (fd < 0)
+		return;
+
+	arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
+	arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
+	arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+	arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
+
+	info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+	if (IS_ERR_OR_NULL(info_linear)) {
+		pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
+		goto out;
+	}
+
+	btf_id = info_linear->info.btf_id;
+
+	info_node = malloc(sizeof(struct bpf_prog_info_node));
+	if (info_node) {
+		info_node->info_linear = info_linear;
+		perf_env__insert_bpf_prog_info(env, info_node);
+	} else
+		free(info_linear);
+
+	if (btf_id == 0)
+		goto out;
+
+	if (btf__get_from_id(btf_id, &btf)) {
+		pr_debug("%s: failed to get BTF of id %u, aborting\n",
+			 __func__, btf_id);
+		goto out;
+	}
+	perf_env__fetch_btf(env, btf_id, btf);
+
+out:
+	free(btf);
+	close(fd);
+}
+
+static int bpf_event__sb_cb(union perf_event *event, void *data)
+{
+	struct perf_env *env = data;
+
+	if (event->header.type != PERF_RECORD_BPF_EVENT)
+		return -1;
+
+	switch (event->bpf_event.type) {
+	case PERF_BPF_EVENT_PROG_LOAD:
+		perf_env__add_bpf_info(env, event->bpf_event.id);
+
+	case PERF_BPF_EVENT_PROG_UNLOAD:
+		/*
+		 * Do not free bpf_prog_info and btf of the program here,
+		 * as annotation still need them. They will be freed at
+		 * the end of the session.
+		 */
+		break;
+	default:
+		pr_debug("unexpected bpf_event type of %d\n",
+			 event->bpf_event.type);
+		break;
+	}
+
+	return 0;
+}
+
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+			    struct perf_env *env)
+{
+	struct perf_event_attr attr = {
+		.type	          = PERF_TYPE_SOFTWARE,
+		.config           = PERF_COUNT_SW_DUMMY,
+		.sample_id_all    = 1,
+		.watermark        = 1,
+		.bpf_event        = 1,
+		.size	   = sizeof(attr), /* to capture ABI version */
+	};
+
+	/*
+	 * Older gcc versions don't support designated initializers, like above,
+	 * for unnamed union members, such as the following:
+	 */
+	attr.wakeup_watermark = 1;
+
+	return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
+}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index b9ec394dc7c7..8cb1189149ec 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -4,12 +4,17 @@
 
 #include <linux/compiler.h>
 #include <linux/rbtree.h>
+#include <pthread.h>
+#include <api/fd/array.h>
 #include "event.h"
 
 struct machine;
 union perf_event;
+struct perf_env;
 struct perf_sample;
 struct record_opts;
+struct evlist;
+struct target;
 
 struct bpf_prog_info_node {
 	struct bpf_prog_info_linear	*info_linear;
@@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
 				      perf_event__handler_t process,
 				      struct machine *machine,
 				      struct record_opts *opts);
+int bpf_event__add_sb_event(struct perf_evlist **evlist,
+				 struct perf_env *env);
+
 #else
 static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
 					     union perf_event *event __maybe_unused,
@@ -46,5 +54,12 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
 {
 	return 0;
 }
+
+static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
+					  struct perf_env *env __maybe_unused)
+{
+	return 0;
+}
+
 #endif // HAVE_LIBBPF_SUPPORT
 #endif

^ permalink raw reply related	[flat|nested] 100+ messages in thread

end of thread, other threads:[~2019-03-22 22:46 UTC | newest]

Thread overview: 100+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-12  5:30 [PATCH v9 perf,bpf 00/15] perf annotation of BPF programs Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 01/15] perf-record: replace option --bpf-event with --no-bpf-event Song Liu
2019-03-22 22:35   ` [tip:perf/urgent] perf record: Replace " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
2019-03-12 13:50   ` Arnaldo Carvalho de Melo
2019-03-22 22:36   ` [tip:perf/urgent] tools lib bpf: Introduce bpf_program__get_prog_info_linear() tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
2019-03-22 22:36   ` [tip:perf/urgent] " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
2019-03-13 21:00   ` Arnaldo Carvalho de Melo
2019-03-13 21:08     ` Arnaldo Carvalho de Melo
2019-03-14  5:08       ` Song Liu
2019-03-14 16:45         ` Song Liu
2019-03-14 18:30           ` Arnaldo Carvalho de Melo
2019-03-22 22:37   ` [tip:perf/urgent] perf bpf: Synthesize " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
2019-03-22 22:37   ` [tip:perf/urgent] perf bpf: Make synthesize_bpf_events() receive perf_session pointer instead of perf_tool tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
2019-03-12 13:10   ` Jiri Olsa
2019-03-12 14:34     ` Arnaldo Carvalho de Melo
2019-03-22 22:38   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
2019-03-12 13:10   ` Jiri Olsa
2019-03-12 14:47     ` Arnaldo Carvalho de Melo
2019-03-13 19:05   ` Arnaldo Carvalho de Melo
2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
2019-03-12 15:00   ` Arnaldo Carvalho de Melo
2019-03-22 22:39   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
2019-03-12 15:14   ` Arnaldo Carvalho de Melo
2019-03-12 15:16     ` Arnaldo Carvalho de Melo
2019-03-12 16:26       ` Song Liu
2019-03-12 17:05         ` Arnaldo Carvalho de Melo
2019-03-12 17:29           ` Song Liu
2019-03-15 19:06             ` Arnaldo Carvalho de Melo
2019-03-15 19:26               ` Arnaldo Carvalho de Melo
2019-03-15 19:31                 ` Song Liu
2019-03-15 19:42                 ` Arnaldo Carvalho de Melo
2019-03-22 22:40   ` [tip:perf/urgent] perf bpf: Save BTF " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
2019-03-22 22:41   ` [tip:perf/urgent] perf top: Add " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
2019-03-22 22:41   ` [tip:perf/urgent] perf feature detection: Add " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
2019-03-18 16:38   ` Arnaldo Carvalho de Melo
2019-03-18 16:43     ` Arnaldo Carvalho de Melo
2019-03-19  6:10       ` Song Liu
2019-03-19 13:37         ` Arnaldo Carvalho de Melo
2019-03-19  6:05     ` Song Liu
2019-03-19 13:37       ` Arnaldo Carvalho de Melo
2019-03-19 13:58       ` Arnaldo Carvalho de Melo
2019-03-19 14:14         ` Arnaldo Carvalho de Melo
2019-03-19 14:52           ` [WORKS!] " Arnaldo Carvalho de Melo
2019-03-19 16:51             ` Song Liu
2019-03-19 16:55               ` Arnaldo Carvalho de Melo
2019-03-19 17:07                 ` Arnaldo Carvalho de Melo
2019-03-22 22:42   ` [tip:perf/urgent] perf symbols: Introduce DSO_BINARY_TYPE__BPF_PROG_INFO tip-bot for Song Liu
2019-03-22 22:43   ` [tip:perf/urgent] perf build: Check what binutils's 'disassembler()' signature to use tip-bot for Song Liu
2019-03-22 22:44   ` [tip:perf/urgent] perf annotate: Enable annotation of BPF programs tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
2019-03-22 22:43   ` [tip:perf/urgent] perf bpf: Process " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 14/15] perf: introduce side band thread Song Liu
2019-03-22 22:45   ` [tip:perf/urgent] perf evlist: Introduce " tip-bot for Song Liu
2019-03-12  5:30 ` [PATCH v9 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
2019-03-19 15:25   ` Arnaldo Carvalho de Melo
2019-03-22 22:45   ` [tip:perf/urgent] perf tools: Save bpf_prog_info and BTF of new BPF programs tip-bot for Song Liu
2019-03-12 13:12 ` [PATCH v9 perf,bpf 00/15] perf annotation of " Jiri Olsa
2019-03-21  9:10 ` Jiri Olsa
2019-03-21 14:12   ` Arnaldo Carvalho de Melo
  -- strict thread matches above, loose matches on Subject: below --
2019-03-07 17:57 [PATCH v7 " Song Liu
2019-03-07 17:57 ` [PATCH v7 perf,bpf 01/15] perf, bpf: consider events with attr.bpf_event as side-band events Song Liu
2019-03-07 17:57 ` [PATCH v7 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear() Song Liu
2019-03-11 18:26   ` Arnaldo Carvalho de Melo
2019-03-11 20:45     ` Daniel Borkmann
2019-03-11 20:57       ` Arnaldo Carvalho de Melo
2019-03-12 11:20         ` Daniel Borkmann
2019-03-07 17:57 ` [PATCH v7 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump() Song Liu
2019-03-07 17:57 ` [PATCH v7 perf,bpf 04/15] perf, bpf: synthesize bpf events with bpf_program__get_prog_info_linear() Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 05/15] perf: change prototype of perf_event__synthesize_bpf_events() Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data Song Liu
2019-03-11 17:56   ` Jiri Olsa
2019-03-11 18:05     ` Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data Song Liu
2019-03-11 17:56   ` Jiri Olsa
2019-03-07 17:58 ` [PATCH v7 perf,bpf 10/15] perf-top: add option --no-bpf-event Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd Song Liu
2019-03-07 23:26   ` Stanislav Fomichev
2019-03-07 23:47     ` Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 12/15] perf, bpf: enable annotation of bpf program Song Liu
2019-03-11 17:56   ` Jiri Olsa
2019-03-11 18:04     ` Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation Song Liu
2019-03-07 17:58 ` [PATCH v7 perf,bpf 14/15] perf: introduce side band thread Song Liu
2019-03-11 17:57   ` Jiri Olsa
2019-03-07 17:58 ` [PATCH v7 perf,bpf 15/15] perf, bpf: save bpf_prog_info and btf of short living bpf programs Song Liu
2019-03-11 13:59 ` [PATCH v7 perf,bpf 00/15] perf annotation of BPF programs Jiri Olsa
2019-03-11 14:16   ` Song Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).