linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names
@ 2024-11-08  6:14 Namhyung Kim
  2024-11-08  6:14 ` [PATCH v2 1/4] perf lock contention: Add and use LCB_F_TYPE_MASK Namhyung Kim
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Namhyung Kim @ 2024-11-08  6:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

Hello,

This is to support symbolization of dynamic locks using slab
allocator's metadata.  The kernel support is in the bpf-next tree now.

It provides the new "kmem_cache" BPF iterator and "bpf_get_kmem_cache"
kfunc to get the information from an address.  The feature detection is
done using BTF type info and it won't have any effect on old kernels.

v2 changes)

 * don't use libbpf_get_error()  (Andrii)

v1) https://lore.kernel.org/linux-perf-users/20241105172635.2463800-1-namhyung@kernel.org

With this change, it can show locks in a slab object like below.  I
added "&" sign to distinguish them from global locks.

    # perf lock con -abl sleep 1
     contended   total wait     max wait     avg wait            address   symbol
    
             2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
             1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
             4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
             2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
             3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
             3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
             1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
             2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
             1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
             1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)

The first two were from "task_struct" slab cache.  It happened to
match with the type name of object but there's no guarantee.  We need
to add type info to slab cache to resolve the lock inside the object.
Anyway, the third one has no dedicated slab cache and was allocated by
kmalloc.

Those slab objects can be used to filter specific locks using -L or
 --lock-filter option.  (It needs quotes to avoid special handling in
the shell).

    # perf lock con -ab -L '&task_struct' sleep 1
       contended   total wait     max wait     avg wait         type   caller
    
               1     25.10 us     25.10 us     25.10 us        mutex   perf_event_exit_task+0x39
               1     21.60 us     21.60 us     21.60 us        mutex   futex_exit_release+0x21
               1      5.56 us      5.56 us      5.56 us        mutex   futex_exec_release+0x21

The code is available at 'perf/lock-slab-v2' branch in my tree

git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git

Thanks,
Namhyung


Namhyung Kim (4):
  perf lock contention: Add and use LCB_F_TYPE_MASK
  perf lock contention: Run BPF slab cache iterator
  perf lock contention: Resolve slab object name using BPF
  perf lock contention: Handle slab objects in -L/--lock-filter option

 tools/perf/builtin-lock.c                     |  39 ++++-
 tools/perf/util/bpf_lock_contention.c         | 140 +++++++++++++++++-
 .../perf/util/bpf_skel/lock_contention.bpf.c  |  70 ++++++++-
 tools/perf/util/bpf_skel/lock_data.h          |  15 +-
 tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |   8 +
 tools/perf/util/lock-contention.h             |   2 +
 6 files changed, 267 insertions(+), 7 deletions(-)

-- 
2.47.0.277.g8800431eea-goog


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

* [PATCH v2 1/4] perf lock contention: Add and use LCB_F_TYPE_MASK
  2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
@ 2024-11-08  6:14 ` Namhyung Kim
  2024-11-08  6:14 ` [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator Namhyung Kim
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Namhyung Kim @ 2024-11-08  6:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

This is a preparation for the later change.  It'll use more bits in the
flags so let's rename the type part and use the mask to extract the
type.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-lock.c            | 4 ++--
 tools/perf/util/bpf_skel/lock_data.h | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 062e2b56a2ab570e..89ee2a2f78603906 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1597,7 +1597,7 @@ static const struct {
 
 static const char *get_type_str(unsigned int flags)
 {
-	flags &= LCB_F_MAX_FLAGS - 1;
+	flags &= LCB_F_TYPE_MASK;
 
 	for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
 		if (lock_type_table[i].flags == flags)
@@ -1608,7 +1608,7 @@ static const char *get_type_str(unsigned int flags)
 
 static const char *get_type_name(unsigned int flags)
 {
-	flags &= LCB_F_MAX_FLAGS - 1;
+	flags &= LCB_F_TYPE_MASK;
 
 	for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
 		if (lock_type_table[i].flags == flags)
diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
index de12892f992f8d43..4f0aae5483745dfa 100644
--- a/tools/perf/util/bpf_skel/lock_data.h
+++ b/tools/perf/util/bpf_skel/lock_data.h
@@ -32,7 +32,8 @@ struct contention_task_data {
 #define LCD_F_MMAP_LOCK		(1U << 31)
 #define LCD_F_SIGHAND_LOCK	(1U << 30)
 
-#define LCB_F_MAX_FLAGS		(1U << 7)
+#define LCB_F_TYPE_MAX		(1U << 7)
+#define LCB_F_TYPE_MASK		0x0000007FU
 
 struct contention_data {
 	u64 total_time;
-- 
2.47.0.277.g8800431eea-goog


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

* [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
  2024-11-08  6:14 ` [PATCH v2 1/4] perf lock contention: Add and use LCB_F_TYPE_MASK Namhyung Kim
@ 2024-11-08  6:14 ` Namhyung Kim
  2024-12-09 16:36   ` Arnaldo Carvalho de Melo
  2024-11-08  6:14 ` [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF Namhyung Kim
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Namhyung Kim @ 2024-11-08  6:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

Recently the kernel got the kmem_cache iterator to traverse metadata of
slab objects.  This can be used to symbolize dynamic locks in a slab.

The new slab_caches hash map will have the pointer of the kmem_cache as
a key and save the name and a id.  The id will be saved in the flags
part of the lock.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/bpf_lock_contention.c         | 50 +++++++++++++++++++
 .../perf/util/bpf_skel/lock_contention.bpf.c  | 28 +++++++++++
 tools/perf/util/bpf_skel/lock_data.h          | 12 +++++
 tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |  8 +++
 4 files changed, 98 insertions(+)

diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index 41a1ad08789511c3..558590c3111390fc 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -12,12 +12,59 @@
 #include <linux/zalloc.h>
 #include <linux/string.h>
 #include <bpf/bpf.h>
+#include <bpf/btf.h>
 #include <inttypes.h>
 
 #include "bpf_skel/lock_contention.skel.h"
 #include "bpf_skel/lock_data.h"
 
 static struct lock_contention_bpf *skel;
+static bool has_slab_iter;
+
+static void check_slab_cache_iter(struct lock_contention *con)
+{
+	struct btf *btf = btf__load_vmlinux_btf();
+	s32 ret;
+
+	if (btf == NULL) {
+		pr_debug("BTF loading failed: %s\n", strerror(errno));
+		return;
+	}
+
+	ret = btf__find_by_name_kind(btf, "bpf_iter__kmem_cache", BTF_KIND_STRUCT);
+	if (ret < 0) {
+		bpf_program__set_autoload(skel->progs.slab_cache_iter, false);
+		pr_debug("slab cache iterator is not available: %d\n", ret);
+		goto out;
+	}
+
+	has_slab_iter = true;
+
+	bpf_map__set_max_entries(skel->maps.slab_caches, con->map_nr_entries);
+out:
+	btf__free(btf);
+}
+
+static void run_slab_cache_iter(void)
+{
+	int fd;
+	char buf[256];
+
+	if (!has_slab_iter)
+		return;
+
+	fd = bpf_iter_create(bpf_link__fd(skel->links.slab_cache_iter));
+	if (fd < 0) {
+		pr_debug("cannot create slab cache iter: %d\n", fd);
+		return;
+	}
+
+	/* This will run the bpf program */
+	while (read(fd, buf, sizeof(buf)) > 0)
+		continue;
+
+	close(fd);
+}
 
 int lock_contention_prepare(struct lock_contention *con)
 {
@@ -109,6 +156,8 @@ int lock_contention_prepare(struct lock_contention *con)
 			skel->rodata->use_cgroup_v2 = 1;
 	}
 
+	check_slab_cache_iter(con);
+
 	if (lock_contention_bpf__load(skel) < 0) {
 		pr_err("Failed to load lock-contention BPF skeleton\n");
 		return -1;
@@ -304,6 +353,7 @@ static void account_end_timestamp(struct lock_contention *con)
 
 int lock_contention_start(void)
 {
+	run_slab_cache_iter();
 	skel->bss->enabled = 1;
 	return 0;
 }
diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
index 1069bda5d733887f..fd24ccb00faec0ba 100644
--- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
+++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
@@ -100,6 +100,13 @@ struct {
 	__uint(max_entries, 1);
 } cgroup_filter SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(long));
+	__uint(value_size, sizeof(struct slab_cache_data));
+	__uint(max_entries, 1);
+} slab_caches SEC(".maps");
+
 struct rw_semaphore___old {
 	struct task_struct *owner;
 } __attribute__((preserve_access_index));
@@ -136,6 +143,8 @@ int perf_subsys_id = -1;
 
 __u64 end_ts;
 
+__u32 slab_cache_id;
+
 /* error stat */
 int task_fail;
 int stack_fail;
@@ -563,4 +572,23 @@ int BPF_PROG(end_timestamp)
 	return 0;
 }
 
+SEC("iter/kmem_cache")
+int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
+{
+	struct kmem_cache *s = ctx->s;
+	struct slab_cache_data d;
+
+	if (s == NULL)
+		return 0;
+
+	d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT;
+	bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name);
+
+	if (d.id >= LCB_F_SLAB_ID_END)
+		return 0;
+
+	bpf_map_update_elem(&slab_caches, &s, &d, BPF_NOEXIST);
+	return 0;
+}
+
 char LICENSE[] SEC("license") = "Dual BSD/GPL";
diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
index 4f0aae5483745dfa..c15f734d7fc4aecb 100644
--- a/tools/perf/util/bpf_skel/lock_data.h
+++ b/tools/perf/util/bpf_skel/lock_data.h
@@ -32,9 +32,16 @@ struct contention_task_data {
 #define LCD_F_MMAP_LOCK		(1U << 31)
 #define LCD_F_SIGHAND_LOCK	(1U << 30)
 
+#define LCB_F_SLAB_ID_SHIFT	16
+#define LCB_F_SLAB_ID_START	(1U << 16)
+#define LCB_F_SLAB_ID_END	(1U << 26)
+#define LCB_F_SLAB_ID_MASK	0x03FF0000U
+
 #define LCB_F_TYPE_MAX		(1U << 7)
 #define LCB_F_TYPE_MASK		0x0000007FU
 
+#define SLAB_NAME_MAX  28
+
 struct contention_data {
 	u64 total_time;
 	u64 min_time;
@@ -55,4 +62,9 @@ enum lock_class_sym {
 	LOCK_CLASS_RQLOCK,
 };
 
+struct slab_cache_data {
+	u32 id;
+	char name[SLAB_NAME_MAX];
+};
+
 #endif /* UTIL_BPF_SKEL_LOCK_DATA_H */
diff --git a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
index 4dcad7b682bdee9c..7b81d3173917fdb5 100644
--- a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
+++ b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
@@ -195,4 +195,12 @@ struct bpf_perf_event_data_kern {
  */
 struct rq {};
 
+struct kmem_cache {
+	const char *name;
+} __attribute__((preserve_access_index));
+
+struct bpf_iter__kmem_cache {
+	struct kmem_cache *s;
+} __attribute__((preserve_access_index));
+
 #endif // __VMLINUX_H
-- 
2.47.0.277.g8800431eea-goog


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

* [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF
  2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
  2024-11-08  6:14 ` [PATCH v2 1/4] perf lock contention: Add and use LCB_F_TYPE_MASK Namhyung Kim
  2024-11-08  6:14 ` [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator Namhyung Kim
@ 2024-11-08  6:14 ` Namhyung Kim
  2024-11-12 11:09   ` Vlastimil Babka
  2024-11-08  6:14 ` [PATCH v2 4/4] perf lock contention: Handle slab objects in -L/--lock-filter option Namhyung Kim
  2024-11-11 19:46 ` [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Ian Rogers
  4 siblings, 1 reply; 19+ messages in thread
From: Namhyung Kim @ 2024-11-08  6:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

The bpf_get_kmem_cache() kfunc can return an address of the slab cache
(kmem_cache).  As it has the name of the slab cache from the iterator,
we can use it to symbolize some dynamic kernel locks in a slab.

Before:
  root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
   contended   total wait     max wait     avg wait            address   symbol

           2      3.34 us      2.87 us      1.67 us   ffff9d7800ad9600    (mutex)
           2      2.16 us      1.93 us      1.08 us   ffff9d7804b992d8    (mutex)
           4      1.37 us       517 ns       343 ns   ffff9d78036e6e00    (mutex)
           1      1.27 us      1.27 us      1.27 us   ffff9d7804b99378    (mutex)
           2       845 ns       599 ns       422 ns   ffffffff9e1c3620   delayed_uprobe_lock (mutex)
           1       845 ns       845 ns       845 ns   ffffffff9da0b280   jiffies_lock (spinlock)
           2       377 ns       259 ns       188 ns   ffffffff9e1cf840   pcpu_alloc_mutex (mutex)
           1       305 ns       305 ns       305 ns   ffffffff9e1b4cf8   tracepoint_srcu_srcu_usage (mutex)
           1       295 ns       295 ns       295 ns   ffffffff9e1c0940   pack_mutex (mutex)
           1       232 ns       232 ns       232 ns   ffff9d7804b7d8d8    (mutex)
           1       180 ns       180 ns       180 ns   ffffffff9e1b4c28   tracepoint_srcu_srcu_usage (mutex)
           1       165 ns       165 ns       165 ns   ffffffff9da8b3a0   text_mutex (mutex)

After:
  root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
   contended   total wait     max wait     avg wait            address   symbol

           2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
           1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
           4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
           2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
           3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
           3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
           1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
           2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
           1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
           1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)

Note that the name starts with '&' sign for slab objects to inform they
are dynamic locks.  It won't give the accurate lock or type names but
it's still useful.  We may add type info to the slab cache later to get
the exact name of the lock in the type later.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/bpf_lock_contention.c         | 52 +++++++++++++++++++
 .../perf/util/bpf_skel/lock_contention.bpf.c  | 21 +++++++-
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index 558590c3111390fc..3f127fc6b95f8326 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -2,6 +2,7 @@
 #include "util/cgroup.h"
 #include "util/debug.h"
 #include "util/evlist.h"
+#include "util/hashmap.h"
 #include "util/machine.h"
 #include "util/map.h"
 #include "util/symbol.h"
@@ -20,12 +21,25 @@
 
 static struct lock_contention_bpf *skel;
 static bool has_slab_iter;
+static struct hashmap slab_hash;
+
+static size_t slab_cache_hash(long key, void *ctx __maybe_unused)
+{
+	return key;
+}
+
+static bool slab_cache_equal(long key1, long key2, void *ctx __maybe_unused)
+{
+	return key1 == key2;
+}
 
 static void check_slab_cache_iter(struct lock_contention *con)
 {
 	struct btf *btf = btf__load_vmlinux_btf();
 	s32 ret;
 
+	hashmap__init(&slab_hash, slab_cache_hash, slab_cache_equal, /*ctx=*/NULL);
+
 	if (btf == NULL) {
 		pr_debug("BTF loading failed: %s\n", strerror(errno));
 		return;
@@ -49,6 +63,7 @@ static void run_slab_cache_iter(void)
 {
 	int fd;
 	char buf[256];
+	long key, *prev_key;
 
 	if (!has_slab_iter)
 		return;
@@ -64,6 +79,34 @@ static void run_slab_cache_iter(void)
 		continue;
 
 	close(fd);
+
+	/* Read the slab cache map and build a hash with IDs */
+	fd = bpf_map__fd(skel->maps.slab_caches);
+	prev_key = NULL;
+	while (!bpf_map_get_next_key(fd, prev_key, &key)) {
+		struct slab_cache_data *data;
+
+		data = malloc(sizeof(*data));
+		if (data == NULL)
+			break;
+
+		if (bpf_map_lookup_elem(fd, &key, data) < 0)
+			break;
+
+		hashmap__add(&slab_hash, data->id, data);
+		prev_key = &key;
+	}
+}
+
+static void exit_slab_cache_iter(void)
+{
+	struct hashmap_entry *cur;
+	unsigned bkt;
+
+	hashmap__for_each_entry(&slab_hash, cur, bkt)
+		free(cur->pvalue);
+
+	hashmap__clear(&slab_hash);
 }
 
 int lock_contention_prepare(struct lock_contention *con)
@@ -397,6 +440,7 @@ static const char *lock_contention_get_name(struct lock_contention *con,
 
 	if (con->aggr_mode == LOCK_AGGR_ADDR) {
 		int lock_fd = bpf_map__fd(skel->maps.lock_syms);
+		struct slab_cache_data *slab_data;
 
 		/* per-process locks set upper bits of the flags */
 		if (flags & LCD_F_MMAP_LOCK)
@@ -415,6 +459,12 @@ static const char *lock_contention_get_name(struct lock_contention *con,
 				return "rq_lock";
 		}
 
+		/* look slab_hash for dynamic locks in a slab object */
+		if (hashmap__find(&slab_hash, flags & LCB_F_SLAB_ID_MASK, &slab_data)) {
+			snprintf(name_buf, sizeof(name_buf), "&%s", slab_data->name);
+			return name_buf;
+		}
+
 		return "";
 	}
 
@@ -589,5 +639,7 @@ int lock_contention_finish(struct lock_contention *con)
 		cgroup__put(cgrp);
 	}
 
+	exit_slab_cache_iter();
+
 	return 0;
 }
diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
index fd24ccb00faec0ba..b5bc37955560a58e 100644
--- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
+++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
@@ -123,6 +123,8 @@ struct mm_struct___new {
 	struct rw_semaphore mmap_lock;
 } __attribute__((preserve_access_index));
 
+extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym __weak;
+
 /* control flags */
 const volatile int has_cpu;
 const volatile int has_task;
@@ -496,8 +498,23 @@ int contention_end(u64 *ctx)
 		};
 		int err;
 
-		if (aggr_mode == LOCK_AGGR_ADDR)
-			first.flags |= check_lock_type(pelem->lock, pelem->flags);
+		if (aggr_mode == LOCK_AGGR_ADDR) {
+			first.flags |= check_lock_type(pelem->lock,
+						       pelem->flags & LCB_F_TYPE_MASK);
+
+			/* Check if it's from a slab object */
+			if (bpf_get_kmem_cache) {
+				struct kmem_cache *s;
+				struct slab_cache_data *d;
+
+				s = bpf_get_kmem_cache(pelem->lock);
+				if (s != NULL) {
+					d = bpf_map_lookup_elem(&slab_caches, &s);
+					if (d != NULL)
+						first.flags |= d->id;
+				}
+			}
+		}
 
 		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
 		if (err < 0) {
-- 
2.47.0.277.g8800431eea-goog


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

* [PATCH v2 4/4] perf lock contention: Handle slab objects in -L/--lock-filter option
  2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
                   ` (2 preceding siblings ...)
  2024-11-08  6:14 ` [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF Namhyung Kim
@ 2024-11-08  6:14 ` Namhyung Kim
  2024-11-11 19:46 ` [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Ian Rogers
  4 siblings, 0 replies; 19+ messages in thread
From: Namhyung Kim @ 2024-11-08  6:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

This is to filter lock contention from specific slab objects only.
Like in the lock symbol output, we can use '&' prefix to filter slab
object names.

  root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
   contended   total wait     max wait     avg wait            address   symbol

           3     14.99 us     14.44 us      5.00 us   ffffffff851c0940   pack_mutex (mutex)
           2      2.75 us      2.56 us      1.38 us   ffff98d7031fb498   &task_struct (mutex)
           4      1.42 us       557 ns       355 ns   ffff98d706311400   &kmalloc-cg-512 (mutex)
           2       953 ns       714 ns       476 ns   ffffffff851c3620   delayed_uprobe_lock (mutex)
           1       929 ns       929 ns       929 ns   ffff98d7031fb538   &task_struct (mutex)
           3       561 ns       210 ns       187 ns   ffffffff84a8b3a0   text_mutex (mutex)
           1       479 ns       479 ns       479 ns   ffffffff851b4cf8   tracepoint_srcu_srcu_usage (mutex)
           2       320 ns       195 ns       160 ns   ffffffff851cf840   pcpu_alloc_mutex (mutex)
           1       212 ns       212 ns       212 ns   ffff98d7031784d8   &signal_cache (mutex)
           1       177 ns       177 ns       177 ns   ffffffff851b4c28   tracepoint_srcu_srcu_usage (mutex)

With the filter, it can show contentions from the task_struct only.

  root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl -L '&task_struct' sleep 1
   contended   total wait     max wait     avg wait            address   symbol

           2      1.97 us      1.71 us       987 ns   ffff98d7032fd658   &task_struct (mutex)
           1      1.20 us      1.20 us      1.20 us   ffff98d7032fd6f8   &task_struct (mutex)

It can work with other aggregation mode:

  root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -ab -L '&task_struct' sleep 1
   contended   total wait     max wait     avg wait         type   caller

           1     25.10 us     25.10 us     25.10 us        mutex   perf_event_exit_task+0x39
           1     21.60 us     21.60 us     21.60 us        mutex   futex_exit_release+0x21
           1      5.56 us      5.56 us      5.56 us        mutex   futex_exec_release+0x21

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-lock.c                     | 35 ++++++++++++++++
 tools/perf/util/bpf_lock_contention.c         | 40 ++++++++++++++++++-
 .../perf/util/bpf_skel/lock_contention.bpf.c  | 21 +++++++++-
 tools/perf/util/lock-contention.h             |  2 +
 4 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 89ee2a2f78603906..405e95666257b7fe 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1646,6 +1646,12 @@ static void lock_filter_finish(void)
 
 	zfree(&filters.cgrps);
 	filters.nr_cgrps = 0;
+
+	for (int i = 0; i < filters.nr_slabs; i++)
+		free(filters.slabs[i]);
+
+	zfree(&filters.slabs);
+	filters.nr_slabs = 0;
 }
 
 static void sort_contention_result(void)
@@ -2412,6 +2418,27 @@ static bool add_lock_sym(char *name)
 	return true;
 }
 
+static bool add_lock_slab(char *name)
+{
+	char **tmp;
+	char *sym = strdup(name);
+
+	if (sym == NULL) {
+		pr_err("Memory allocation failure\n");
+		return false;
+	}
+
+	tmp = realloc(filters.slabs, (filters.nr_slabs + 1) * sizeof(*filters.slabs));
+	if (tmp == NULL) {
+		pr_err("Memory allocation failure\n");
+		return false;
+	}
+
+	tmp[filters.nr_slabs++] = sym;
+	filters.slabs = tmp;
+	return true;
+}
+
 static int parse_lock_addr(const struct option *opt __maybe_unused, const char *str,
 			   int unset __maybe_unused)
 {
@@ -2435,6 +2462,14 @@ static int parse_lock_addr(const struct option *opt __maybe_unused, const char *
 			continue;
 		}
 
+		if (*tok == '&') {
+			if (!add_lock_slab(tok + 1)) {
+				ret = -1;
+				break;
+			}
+			continue;
+		}
+
 		/*
 		 * At this moment, we don't have kernel symbols.  Save the symbols
 		 * in a separate list and resolve them to addresses later.
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index 3f127fc6b95f8326..5ca1c7ffe4ce5073 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -112,7 +112,7 @@ static void exit_slab_cache_iter(void)
 int lock_contention_prepare(struct lock_contention *con)
 {
 	int i, fd;
-	int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1, ncgrps = 1;
+	int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1, ncgrps = 1, nslabs = 1;
 	struct evlist *evlist = con->evlist;
 	struct target *target = con->target;
 
@@ -201,6 +201,13 @@ int lock_contention_prepare(struct lock_contention *con)
 
 	check_slab_cache_iter(con);
 
+	if (con->filters->nr_slabs && has_slab_iter) {
+		skel->rodata->has_slab = 1;
+		nslabs = con->filters->nr_slabs;
+	}
+
+	bpf_map__set_max_entries(skel->maps.slab_filter, nslabs);
+
 	if (lock_contention_bpf__load(skel) < 0) {
 		pr_err("Failed to load lock-contention BPF skeleton\n");
 		return -1;
@@ -271,6 +278,36 @@ int lock_contention_prepare(struct lock_contention *con)
 	bpf_program__set_autoload(skel->progs.collect_lock_syms, false);
 
 	lock_contention_bpf__attach(skel);
+
+	/* run the slab iterator after attaching */
+	run_slab_cache_iter();
+
+	if (con->filters->nr_slabs) {
+		u8 val = 1;
+		int cache_fd;
+		long key, *prev_key;
+
+		fd = bpf_map__fd(skel->maps.slab_filter);
+
+		/* Read the slab cache map and build a hash with its address */
+		cache_fd = bpf_map__fd(skel->maps.slab_caches);
+		prev_key = NULL;
+		while (!bpf_map_get_next_key(cache_fd, prev_key, &key)) {
+			struct slab_cache_data data;
+
+			if (bpf_map_lookup_elem(cache_fd, &key, &data) < 0)
+				break;
+
+			for (i = 0; i < con->filters->nr_slabs; i++) {
+				if (!strcmp(con->filters->slabs[i], data.name)) {
+					bpf_map_update_elem(fd, &key, &val, BPF_ANY);
+					break;
+				}
+			}
+			prev_key = &key;
+		}
+	}
+
 	return 0;
 }
 
@@ -396,7 +433,6 @@ static void account_end_timestamp(struct lock_contention *con)
 
 int lock_contention_start(void)
 {
-	run_slab_cache_iter();
 	skel->bss->enabled = 1;
 	return 0;
 }
diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
index b5bc37955560a58e..048a04fc3a7fc27d 100644
--- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
+++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
@@ -100,6 +100,13 @@ struct {
 	__uint(max_entries, 1);
 } cgroup_filter SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(long));
+	__uint(value_size, sizeof(__u8));
+	__uint(max_entries, 1);
+} slab_filter SEC(".maps");
+
 struct {
 	__uint(type, BPF_MAP_TYPE_HASH);
 	__uint(key_size, sizeof(long));
@@ -131,6 +138,7 @@ const volatile int has_task;
 const volatile int has_type;
 const volatile int has_addr;
 const volatile int has_cgroup;
+const volatile int has_slab;
 const volatile int needs_callstack;
 const volatile int stack_skip;
 const volatile int lock_owner;
@@ -213,7 +221,7 @@ static inline int can_record(u64 *ctx)
 		__u64 addr = ctx[0];
 
 		ok = bpf_map_lookup_elem(&addr_filter, &addr);
-		if (!ok)
+		if (!ok && !has_slab)
 			return 0;
 	}
 
@@ -226,6 +234,17 @@ static inline int can_record(u64 *ctx)
 			return 0;
 	}
 
+	if (has_slab && bpf_get_kmem_cache) {
+		__u8 *ok;
+		__u64 addr = ctx[0];
+		long kmem_cache_addr;
+
+		kmem_cache_addr = (long)bpf_get_kmem_cache(addr);
+		ok = bpf_map_lookup_elem(&slab_filter, &kmem_cache_addr);
+		if (!ok)
+			return 0;
+	}
+
 	return 1;
 }
 
diff --git a/tools/perf/util/lock-contention.h b/tools/perf/util/lock-contention.h
index 1a7248ff388947e1..95331b6ec062410d 100644
--- a/tools/perf/util/lock-contention.h
+++ b/tools/perf/util/lock-contention.h
@@ -10,10 +10,12 @@ struct lock_filter {
 	int			nr_addrs;
 	int			nr_syms;
 	int			nr_cgrps;
+	int			nr_slabs;
 	unsigned int		*types;
 	unsigned long		*addrs;
 	char			**syms;
 	u64			*cgrps;
+	char			**slabs;
 };
 
 struct lock_stat {
-- 
2.47.0.277.g8800431eea-goog


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

* Re: [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names
  2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
                   ` (3 preceding siblings ...)
  2024-11-08  6:14 ` [PATCH v2 4/4] perf lock contention: Handle slab objects in -L/--lock-filter option Namhyung Kim
@ 2024-11-11 19:46 ` Ian Rogers
  2024-11-18 18:35   ` Namhyung Kim
  4 siblings, 1 reply; 19+ messages in thread
From: Ian Rogers @ 2024-11-11 19:46 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Vlastimil Babka,
	Roman Gushchin, Hyeonggon Yoo, Kees Cook

On Thu, Nov 7, 2024 at 10:15 PM Namhyung Kim <namhyung@kernel.org> wrote:
>
> Hello,
>
> This is to support symbolization of dynamic locks using slab
> allocator's metadata.  The kernel support is in the bpf-next tree now.
>
> It provides the new "kmem_cache" BPF iterator and "bpf_get_kmem_cache"
> kfunc to get the information from an address.  The feature detection is
> done using BTF type info and it won't have any effect on old kernels.
>
> v2 changes)
>
>  * don't use libbpf_get_error()  (Andrii)
>
> v1) https://lore.kernel.org/linux-perf-users/20241105172635.2463800-1-namhyung@kernel.org
>
> With this change, it can show locks in a slab object like below.  I
> added "&" sign to distinguish them from global locks.

I know the & is intentional but I worry it could later complicate
parsing of filters. Perhaps @ is a viable alternative. Other than
that:

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

>     # perf lock con -abl sleep 1
>      contended   total wait     max wait     avg wait            address   symbol
>
>              2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
>              1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
>              4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
>              2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
>              3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
>              3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
>              1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
>              2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
>              1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
>              1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)
>
> The first two were from "task_struct" slab cache.  It happened to
> match with the type name of object but there's no guarantee.  We need
> to add type info to slab cache to resolve the lock inside the object.
> Anyway, the third one has no dedicated slab cache and was allocated by
> kmalloc.
>
> Those slab objects can be used to filter specific locks using -L or
>  --lock-filter option.  (It needs quotes to avoid special handling in
> the shell).
>
>     # perf lock con -ab -L '&task_struct' sleep 1
>        contended   total wait     max wait     avg wait         type   caller
>
>                1     25.10 us     25.10 us     25.10 us        mutex   perf_event_exit_task+0x39
>                1     21.60 us     21.60 us     21.60 us        mutex   futex_exit_release+0x21
>                1      5.56 us      5.56 us      5.56 us        mutex   futex_exec_release+0x21
>
> The code is available at 'perf/lock-slab-v2' branch in my tree
>
> git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git
>
> Thanks,
> Namhyung
>
>
> Namhyung Kim (4):
>   perf lock contention: Add and use LCB_F_TYPE_MASK
>   perf lock contention: Run BPF slab cache iterator
>   perf lock contention: Resolve slab object name using BPF
>   perf lock contention: Handle slab objects in -L/--lock-filter option
>
>  tools/perf/builtin-lock.c                     |  39 ++++-
>  tools/perf/util/bpf_lock_contention.c         | 140 +++++++++++++++++-
>  .../perf/util/bpf_skel/lock_contention.bpf.c  |  70 ++++++++-
>  tools/perf/util/bpf_skel/lock_data.h          |  15 +-
>  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |   8 +
>  tools/perf/util/lock-contention.h             |   2 +
>  6 files changed, 267 insertions(+), 7 deletions(-)
>
> --
> 2.47.0.277.g8800431eea-goog
>

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

* Re: [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF
  2024-11-08  6:14 ` [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF Namhyung Kim
@ 2024-11-12 11:09   ` Vlastimil Babka
  2024-11-12 14:50     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 19+ messages in thread
From: Vlastimil Babka @ 2024-11-12 11:09 UTC (permalink / raw)
  To: Namhyung Kim, Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang
  Cc: Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Roman Gushchin, Hyeonggon Yoo, Kees Cook

On 11/8/24 07:14, Namhyung Kim wrote:
> The bpf_get_kmem_cache() kfunc can return an address of the slab cache
> (kmem_cache).  As it has the name of the slab cache from the iterator,
> we can use it to symbolize some dynamic kernel locks in a slab.
> 
> Before:
>   root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
>    contended   total wait     max wait     avg wait            address   symbol
> 
>            2      3.34 us      2.87 us      1.67 us   ffff9d7800ad9600    (mutex)
>            2      2.16 us      1.93 us      1.08 us   ffff9d7804b992d8    (mutex)
>            4      1.37 us       517 ns       343 ns   ffff9d78036e6e00    (mutex)
>            1      1.27 us      1.27 us      1.27 us   ffff9d7804b99378    (mutex)
>            2       845 ns       599 ns       422 ns   ffffffff9e1c3620   delayed_uprobe_lock (mutex)
>            1       845 ns       845 ns       845 ns   ffffffff9da0b280   jiffies_lock (spinlock)
>            2       377 ns       259 ns       188 ns   ffffffff9e1cf840   pcpu_alloc_mutex (mutex)
>            1       305 ns       305 ns       305 ns   ffffffff9e1b4cf8   tracepoint_srcu_srcu_usage (mutex)
>            1       295 ns       295 ns       295 ns   ffffffff9e1c0940   pack_mutex (mutex)
>            1       232 ns       232 ns       232 ns   ffff9d7804b7d8d8    (mutex)
>            1       180 ns       180 ns       180 ns   ffffffff9e1b4c28   tracepoint_srcu_srcu_usage (mutex)
>            1       165 ns       165 ns       165 ns   ffffffff9da8b3a0   text_mutex (mutex)
> 
> After:
>   root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
>    contended   total wait     max wait     avg wait            address   symbol
> 
>            2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
>            1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
>            4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
>            2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
>            3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
>            3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
>            1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
>            2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
>            1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
>            1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)
> 
> Note that the name starts with '&' sign for slab objects to inform they
> are dynamic locks.  It won't give the accurate lock or type names but
> it's still useful.  We may add type info to the slab cache later to get
> the exact name of the lock in the type later.
> 
> Signed-off-by: Namhyung Kim <namhyung@kernel.org>

<snip>

> diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> index fd24ccb00faec0ba..b5bc37955560a58e 100644
> --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> @@ -123,6 +123,8 @@ struct mm_struct___new {
>  	struct rw_semaphore mmap_lock;
>  } __attribute__((preserve_access_index));
>  
> +extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym __weak;
> +
>  /* control flags */
>  const volatile int has_cpu;
>  const volatile int has_task;
> @@ -496,8 +498,23 @@ int contention_end(u64 *ctx)
>  		};
>  		int err;
>  
> -		if (aggr_mode == LOCK_AGGR_ADDR)
> -			first.flags |= check_lock_type(pelem->lock, pelem->flags);
> +		if (aggr_mode == LOCK_AGGR_ADDR) {
> +			first.flags |= check_lock_type(pelem->lock,
> +						       pelem->flags & LCB_F_TYPE_MASK);
> +
> +			/* Check if it's from a slab object */
> +			if (bpf_get_kmem_cache) {
> +				struct kmem_cache *s;
> +				struct slab_cache_data *d;
> +
> +				s = bpf_get_kmem_cache(pelem->lock);
> +				if (s != NULL) {
> +					d = bpf_map_lookup_elem(&slab_caches, &s);
> +					if (d != NULL)
> +						first.flags |= d->id;
> +				}

Is this being executed as part of obtaining a perf event record, or as part
of a postprocessing pass? I'm not familiar enough with the code to be certain.

- if it's part of perf event record, can you just store 's' and defer
resolving the cache by bpf_map_lookup_elem() to postprocessing?
- if it's postprocessing, it would be too late for bpf_get_kmem_cache() as
the object might be gone already?

The second alternative would be worse as it could miss the cache or
misattribute (in case page is reallocated by another cache), the first is
just less efficient than possible.

> +			}
> +		}
>  
>  		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
>  		if (err < 0) {


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

* Re: [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF
  2024-11-12 11:09   ` Vlastimil Babka
@ 2024-11-12 14:50     ` Arnaldo Carvalho de Melo
  2024-11-13 14:20       ` Vlastimil Babka
  0 siblings, 1 reply; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2024-11-12 14:50 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Namhyung Kim, Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On Tue, Nov 12, 2024 at 12:09:24PM +0100, Vlastimil Babka wrote:
> On 11/8/24 07:14, Namhyung Kim wrote:
> > The bpf_get_kmem_cache() kfunc can return an address of the slab cache
> > (kmem_cache).  As it has the name of the slab cache from the iterator,
> > we can use it to symbolize some dynamic kernel locks in a slab.
> > 
> > Before:
> >   root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
> >    contended   total wait     max wait     avg wait            address   symbol
> > 
> >            2      3.34 us      2.87 us      1.67 us   ffff9d7800ad9600    (mutex)
> >            2      2.16 us      1.93 us      1.08 us   ffff9d7804b992d8    (mutex)
> >            4      1.37 us       517 ns       343 ns   ffff9d78036e6e00    (mutex)
> >            1      1.27 us      1.27 us      1.27 us   ffff9d7804b99378    (mutex)
> >            2       845 ns       599 ns       422 ns   ffffffff9e1c3620   delayed_uprobe_lock (mutex)
> >            1       845 ns       845 ns       845 ns   ffffffff9da0b280   jiffies_lock (spinlock)
> >            2       377 ns       259 ns       188 ns   ffffffff9e1cf840   pcpu_alloc_mutex (mutex)
> >            1       305 ns       305 ns       305 ns   ffffffff9e1b4cf8   tracepoint_srcu_srcu_usage (mutex)
> >            1       295 ns       295 ns       295 ns   ffffffff9e1c0940   pack_mutex (mutex)
> >            1       232 ns       232 ns       232 ns   ffff9d7804b7d8d8    (mutex)
> >            1       180 ns       180 ns       180 ns   ffffffff9e1b4c28   tracepoint_srcu_srcu_usage (mutex)
> >            1       165 ns       165 ns       165 ns   ffffffff9da8b3a0   text_mutex (mutex)
> > 
> > After:
> >   root@virtme-ng:/home/namhyung/project/linux# tools/perf/perf lock con -abl sleep 1
> >    contended   total wait     max wait     avg wait            address   symbol
> > 
> >            2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
> >            1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
> >            4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
> >            2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
> >            3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
> >            3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
> >            1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
> >            2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
> >            1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
> >            1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)
> > 
> > Note that the name starts with '&' sign for slab objects to inform they
> > are dynamic locks.  It won't give the accurate lock or type names but
> > it's still useful.  We may add type info to the slab cache later to get
> > the exact name of the lock in the type later.
> > 
> > Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> 
> <snip>
> 
> > diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > index fd24ccb00faec0ba..b5bc37955560a58e 100644
> > --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > @@ -123,6 +123,8 @@ struct mm_struct___new {
> >  	struct rw_semaphore mmap_lock;
> >  } __attribute__((preserve_access_index));
> >  
> > +extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym __weak;
> > +
> >  /* control flags */
> >  const volatile int has_cpu;
> >  const volatile int has_task;
> > @@ -496,8 +498,23 @@ int contention_end(u64 *ctx)
> >  		};
> >  		int err;
> >  
> > -		if (aggr_mode == LOCK_AGGR_ADDR)
> > -			first.flags |= check_lock_type(pelem->lock, pelem->flags);
> > +		if (aggr_mode == LOCK_AGGR_ADDR) {
> > +			first.flags |= check_lock_type(pelem->lock,
> > +						       pelem->flags & LCB_F_TYPE_MASK);
> > +
> > +			/* Check if it's from a slab object */
> > +			if (bpf_get_kmem_cache) {
> > +				struct kmem_cache *s;
> > +				struct slab_cache_data *d;
> > +
> > +				s = bpf_get_kmem_cache(pelem->lock);
> > +				if (s != NULL) {
> > +					d = bpf_map_lookup_elem(&slab_caches, &s);
> > +					if (d != NULL)
> > +						first.flags |= d->id;
> > +				}
> 
> Is this being executed as part of obtaining a perf event record, or as part
> of a postprocessing pass? I'm not familiar enough with the code to be certain.
> 
> - if it's part of perf event record, can you just store 's' and defer
> resolving the cache by bpf_map_lookup_elem() to postprocessing?

Namhyung is in vacation this week, so lemme try to help (and learn more
about this patchset since we discussed about it back in LSFMM :-)):

tldr;: He wants to store a 10 bit cookie for the slab cache, to avoid
storing 64 bits per contention record.

My reading of his code:

'first' is a 'struct contention_data' instance, that he will use for
post processing in tools/perf/builtin-lock.c, the relevant part:

	if (use_bpf) {
                lock_contention_start();
                if (argc)
                        evlist__start_workload(con.evlist);

                /* wait for signal */
                pause();

                lock_contention_stop();
                lock_contention_read(&con);
	} else
		process records from a perf.data file with tons
		of lock:lock_contention_{begin,end}, which the use_bpf
		mode above "pre-processes" at begin+end pairs and
                turns into 'struct contention_data' records in a BPF
		map for later post processing in the common part after
		this if/else block.

The post processing is in lock_contention_read(), that is in
tools/perf/util/bpf_lock_contention.c, I stripped out prep steps, etc,
the "meat" is:

        struct contention_data data = {};
	struct lock_stat *st = NULL;
<SNIP>
        while (!bpf_map_get_next_key(fd, prev_key, &key)) {
                s64 ls_key;
                const char *name;

                bpf_map_lookup_elem(fd, &key, &data);

                name = lock_contention_get_name(con, &key, stack_trace, data.flags);
                st = lock_stat_findnew(ls_key, name, data.flags);

That 'lock_stat' struct is then filled up and later, in the common part
to using or not BPF, it gets printed out in the builtin-lock.c main tool
codebase.

The part we're interested here is that lock_contention_get_name(), that
before this patch series returns "(mutex)" and now resolves it to the
slab cache name "&task_struct (mutex)".

key is:

struct contention_key {
        s32 stack_id;
        u32 pid;
        u64 lock_addr_or_cgroup;
};

lock_contention_get_name() tries to resolve the name to the usual
suspects: 
                /* per-process locks set upper bits of the flags */
                if (flags & LCD_F_MMAP_LOCK)
                        return "mmap_lock";
                if (flags & LCD_F_SIGHAND_LOCK)
                        return "siglock";

                /* global locks with symbols */
                sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, &kmap);
                if (sym)
                        return sym->name;

And then if all of the above (there is another case for rq_lock) it
then gets to look the the ID area of contention_data->flags:

+#define LCB_F_SLAB_ID_SHIFT    16
+#define LCB_F_SLAB_ID_START    (1U << 16)
+#define LCB_F_SLAB_ID_END	(1U << 26)
+#define LCB_F_SLAB_ID_MASK     0x03FF0000U

>>> bin(0x03FF0000)
'0b11111111110000000000000000'
>>>

+               /* look slab_hash for dynamic locks in a slab object */
+               if (hashmap__find(&slab_hash, flags & LCB_F_SLAB_ID_MASK, &slab_data)) {
+                       snprintf(name_buf, sizeof(name_buf), "&%s", slab_data->name);
+                       return name_buf;
+        	}

He wants to avoid storing 64 bytes (the slab cache pointer, 's'), instead
he wants to store a shorter 'id' and encode it in the upper bits of the
'struct contention_data' 'flags' field.

The iterator, at the beggining of the session attributes this id,
starting from zero, to each of the slab caches, so it needs to map it
back from the address at contention_end tracepoint.

At post processing time it converts the id back to the name of the slab
cache.

I hope this helps,

- Arnaldo

> - if it's postprocessing, it would be too late for bpf_get_kmem_cache() as
> the object might be gone already?
> 
> The second alternative would be worse as it could miss the cache or
> misattribute (in case page is reallocated by another cache), the first is
> just less efficient than possible.
> 
> > +			}
> > +		}
> >  
> >  		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
> >  		if (err < 0) {

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

* Re: [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF
  2024-11-12 14:50     ` Arnaldo Carvalho de Melo
@ 2024-11-13 14:20       ` Vlastimil Babka
  2024-11-18 18:45         ` Namhyung Kim
  0 siblings, 1 reply; 19+ messages in thread
From: Vlastimil Babka @ 2024-11-13 14:20 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On 11/12/24 15:50, Arnaldo Carvalho de Melo wrote:
> On Tue, Nov 12, 2024 at 12:09:24PM +0100, Vlastimil Babka wrote:
> +               /* look slab_hash for dynamic locks in a slab object */
> +               if (hashmap__find(&slab_hash, flags & LCB_F_SLAB_ID_MASK, &slab_data)) {
> +                       snprintf(name_buf, sizeof(name_buf), "&%s", slab_data->name);
> +                       return name_buf;
> +        	}
> 
> He wants to avoid storing 64 bytes (the slab cache pointer, 's'), instead
> he wants to store a shorter 'id' and encode it in the upper bits of the
> 'struct contention_data' 'flags' field.
> 
> The iterator, at the beggining of the session attributes this id,
> starting from zero, to each of the slab caches, so it needs to map it
> back from the address at contention_end tracepoint.
> 
> At post processing time it converts the id back to the name of the slab
> cache.
> 
> I hope this helps,

Thanks a lot, if it's a tradeoff to do a bit more work in order to store
less data, then it makes sense to me.

Vlastimil

> - Arnaldo
> 
>> - if it's postprocessing, it would be too late for bpf_get_kmem_cache() as
>> the object might be gone already?
>> 
>> The second alternative would be worse as it could miss the cache or
>> misattribute (in case page is reallocated by another cache), the first is
>> just less efficient than possible.
>> 
>> > +			}
>> > +		}
>> >  
>> >  		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
>> >  		if (err < 0) {


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

* Re: [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names
  2024-11-11 19:46 ` [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Ian Rogers
@ 2024-11-18 18:35   ` Namhyung Kim
  2024-12-13 17:10     ` Namhyung Kim
  0 siblings, 1 reply; 19+ messages in thread
From: Namhyung Kim @ 2024-11-18 18:35 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Vlastimil Babka,
	Roman Gushchin, Hyeonggon Yoo, Kees Cook

On Mon, Nov 11, 2024 at 11:46:37AM -0800, Ian Rogers wrote:
> On Thu, Nov 7, 2024 at 10:15 PM Namhyung Kim <namhyung@kernel.org> wrote:
> >
> > Hello,
> >
> > This is to support symbolization of dynamic locks using slab
> > allocator's metadata.  The kernel support is in the bpf-next tree now.
> >
> > It provides the new "kmem_cache" BPF iterator and "bpf_get_kmem_cache"
> > kfunc to get the information from an address.  The feature detection is
> > done using BTF type info and it won't have any effect on old kernels.
> >
> > v2 changes)
> >
> >  * don't use libbpf_get_error()  (Andrii)
> >
> > v1) https://lore.kernel.org/linux-perf-users/20241105172635.2463800-1-namhyung@kernel.org
> >
> > With this change, it can show locks in a slab object like below.  I
> > added "&" sign to distinguish them from global locks.
> 
> I know the & is intentional but I worry it could later complicate
> parsing of filters. Perhaps @ is a viable alternative. Other than
> that:
> 
> Acked-by: Ian Rogers <irogers@google.com>

Thanks for the review!

I don't think it clashes with BPF sample filters which works on sample
data generated from a perf_event.  Technically this command doesn't use
perf_event and just attaches the BPF program to tracepoint directly.

Also sample filters don't use '&' symbol in the syntax as of now. :)

Thanks,
Namhyung

> 
> >     # perf lock con -abl sleep 1
> >      contended   total wait     max wait     avg wait            address   symbol
> >
> >              2      1.95 us      1.77 us       975 ns   ffff9d5e852d3498   &task_struct (mutex)
> >              1      1.18 us      1.18 us      1.18 us   ffff9d5e852d3538   &task_struct (mutex)
> >              4      1.12 us       354 ns       279 ns   ffff9d5e841ca800   &kmalloc-cg-512 (mutex)
> >              2       859 ns       617 ns       429 ns   ffffffffa41c3620   delayed_uprobe_lock (mutex)
> >              3       691 ns       388 ns       230 ns   ffffffffa41c0940   pack_mutex (mutex)
> >              3       421 ns       164 ns       140 ns   ffffffffa3a8b3a0   text_mutex (mutex)
> >              1       409 ns       409 ns       409 ns   ffffffffa41b4cf8   tracepoint_srcu_srcu_usage (mutex)
> >              2       362 ns       239 ns       181 ns   ffffffffa41cf840   pcpu_alloc_mutex (mutex)
> >              1       220 ns       220 ns       220 ns   ffff9d5e82b534d8   &signal_cache (mutex)
> >              1       215 ns       215 ns       215 ns   ffffffffa41b4c28   tracepoint_srcu_srcu_usage (mutex)
> >
> > The first two were from "task_struct" slab cache.  It happened to
> > match with the type name of object but there's no guarantee.  We need
> > to add type info to slab cache to resolve the lock inside the object.
> > Anyway, the third one has no dedicated slab cache and was allocated by
> > kmalloc.
> >
> > Those slab objects can be used to filter specific locks using -L or
> >  --lock-filter option.  (It needs quotes to avoid special handling in
> > the shell).
> >
> >     # perf lock con -ab -L '&task_struct' sleep 1
> >        contended   total wait     max wait     avg wait         type   caller
> >
> >                1     25.10 us     25.10 us     25.10 us        mutex   perf_event_exit_task+0x39
> >                1     21.60 us     21.60 us     21.60 us        mutex   futex_exit_release+0x21
> >                1      5.56 us      5.56 us      5.56 us        mutex   futex_exec_release+0x21
> >
> > The code is available at 'perf/lock-slab-v2' branch in my tree
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git
> >
> > Thanks,
> > Namhyung
> >
> >
> > Namhyung Kim (4):
> >   perf lock contention: Add and use LCB_F_TYPE_MASK
> >   perf lock contention: Run BPF slab cache iterator
> >   perf lock contention: Resolve slab object name using BPF
> >   perf lock contention: Handle slab objects in -L/--lock-filter option
> >
> >  tools/perf/builtin-lock.c                     |  39 ++++-
> >  tools/perf/util/bpf_lock_contention.c         | 140 +++++++++++++++++-
> >  .../perf/util/bpf_skel/lock_contention.bpf.c  |  70 ++++++++-
> >  tools/perf/util/bpf_skel/lock_data.h          |  15 +-
> >  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |   8 +
> >  tools/perf/util/lock-contention.h             |   2 +
> >  6 files changed, 267 insertions(+), 7 deletions(-)
> >
> > --
> > 2.47.0.277.g8800431eea-goog
> >

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

* Re: [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF
  2024-11-13 14:20       ` Vlastimil Babka
@ 2024-11-18 18:45         ` Namhyung Kim
  0 siblings, 0 replies; 19+ messages in thread
From: Namhyung Kim @ 2024-11-18 18:45 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Arnaldo Carvalho de Melo, Ian Rogers, Kan Liang, Jiri Olsa,
	Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Roman Gushchin, Hyeonggon Yoo, Kees Cook

Hello,

On Wed, Nov 13, 2024 at 03:20:43PM +0100, Vlastimil Babka wrote:
> On 11/12/24 15:50, Arnaldo Carvalho de Melo wrote:
> > On Tue, Nov 12, 2024 at 12:09:24PM +0100, Vlastimil Babka wrote:
> > +               /* look slab_hash for dynamic locks in a slab object */
> > +               if (hashmap__find(&slab_hash, flags & LCB_F_SLAB_ID_MASK, &slab_data)) {
> > +                       snprintf(name_buf, sizeof(name_buf), "&%s", slab_data->name);
> > +                       return name_buf;
> > +        	}
> > 
> > He wants to avoid storing 64 bytes (the slab cache pointer, 's'), instead
> > he wants to store a shorter 'id' and encode it in the upper bits of the
> > 'struct contention_data' 'flags' field.
> > 
> > The iterator, at the beggining of the session attributes this id,
> > starting from zero, to each of the slab caches, so it needs to map it
> > back from the address at contention_end tracepoint.
> > 
> > At post processing time it converts the id back to the name of the slab
> > cache.
> > 
> > I hope this helps,

Thanks Analdo for the explanation!

> 
> Thanks a lot, if it's a tradeoff to do a bit more work in order to store
> less data, then it makes sense to me.

Right, I don't want to increase the data size for this as we have some
unused bits in the flags.  It'd call one more bpf hashmap lookup during
record but I don't think it's gonna be a problem.

Thanks,
Namhyung

> > 
> >> - if it's postprocessing, it would be too late for bpf_get_kmem_cache() as
> >> the object might be gone already?
> >> 
> >> The second alternative would be worse as it could miss the cache or
> >> misattribute (in case page is reallocated by another cache), the first is
> >> just less efficient than possible.
> >> 
> >> > +			}
> >> > +		}
> >> >  
> >> >  		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
> >> >  		if (err < 0) {
> 

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-11-08  6:14 ` [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator Namhyung Kim
@ 2024-12-09 16:36   ` Arnaldo Carvalho de Melo
  2024-12-09 16:38     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2024-12-09 16:36 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra,
	Ingo Molnar, LKML, linux-perf-users, Andrii Nakryiko, Song Liu,
	bpf, Stephane Eranian, Vlastimil Babka, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> Recently the kernel got the kmem_cache iterator to traverse metadata of
> slab objects.  This can be used to symbolize dynamic locks in a slab.
> 
> The new slab_caches hash map will have the pointer of the kmem_cache as
> a key and save the name and a id.  The id will be saved in the flags
> part of the lock.

Trying to fix this 

cd . && make GEN_VMLINUX_H=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j28 O=/tmp/tmp.DWo9tIFvWU DESTDIR=/tmp/tmp.ex3iljqLBT
  BUILD:   Doing 'make -j28' parallel build
Warning: Kernel ABI header differences:
  diff -u tools/include/uapi/drm/drm.h include/uapi/drm/drm.h
  diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h
  diff -u tools/include/uapi/linux/perf_event.h include/uapi/linux/perf_event.h
  diff -u tools/arch/x86/include/asm/cpufeatures.h arch/x86/include/asm/cpufeatures.h
  diff -u tools/arch/x86/include/uapi/asm/kvm.h arch/x86/include/uapi/asm/kvm.h
  diff -u tools/arch/arm64/include/uapi/asm/kvm.h arch/arm64/include/uapi/asm/kvm.h
  diff -u tools/arch/arm64/include/uapi/asm/unistd.h arch/arm64/include/uapi/asm/unistd.h
  diff -u tools/include/uapi/asm-generic/unistd.h include/uapi/asm-generic/unistd.h
  diff -u tools/include/uapi/asm-generic/mman.h include/uapi/asm-generic/mman.h
  diff -u tools/perf/arch/x86/entry/syscalls/syscall_32.tbl arch/x86/entry/syscalls/syscall_32.tbl
  diff -u tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
  diff -u tools/perf/arch/powerpc/entry/syscalls/syscall.tbl arch/powerpc/kernel/syscalls/syscall.tbl
  diff -u tools/perf/arch/s390/entry/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl
  diff -u tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl arch/mips/kernel/syscalls/syscall_n64.tbl
  diff -u tools/perf/trace/beauty/include/uapi/linux/fcntl.h include/uapi/linux/fcntl.h
  diff -u tools/perf/trace/beauty/include/uapi/linux/mount.h include/uapi/linux/mount.h
  diff -u tools/perf/trace/beauty/include/uapi/linux/prctl.h include/uapi/linux/prctl.h
Makefile.config:989: No libllvm 13+ found, slower source file resolution, please install llvm-devel/llvm-dev
Makefile.config:1171: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel

  GEN     /tmp/tmp.DWo9tIFvWU/common-cmds.h
  CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v0.o
  CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v2.o
  CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-show-cycles.o
  GEN     /tmp/tmp.DWo9tIFvWU/arch/arm64/include/generated/asm/sysreg-defs.h
  LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v2.so
  LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-show-cycles.so
  LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v0.so
  PERF_VERSION = 6.13.rc1.g61c6ae4ddd41
  GEN     perf-iostat
  GEN     perf-archive
  INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/exec-cmd.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/help.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/pager.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/parse-options.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/run-command.h
  INSTALL libsubcmd_headers
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/bpf_perf.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/core.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/cpumap.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/threadmap.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/evlist.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/evsel.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/event.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/mmap.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/core.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/cpumap.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/evlist.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/cpu.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/cpumap.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libsymbol/include/symbol/kallsyms.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/evsel.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/io.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/debug.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/lib.h
  CC      /tmp/tmp.DWo9tIFvWU/libsymbol/kallsyms.o
  CC      /tmp/tmp.DWo9tIFvWU/libperf/threadmap.o
  GEN     /tmp/tmp.DWo9tIFvWU/libbpf/bpf_helper_defs.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/mmap.h
  MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf
  CC      /tmp/tmp.DWo9tIFvWU/libperf/evsel.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/rc_check.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fd/array.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/threadmap.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/evlist.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fs/fs.h
  CC      /tmp/tmp.DWo9tIFvWU/libapi/cpu.o
  INSTALL libsymbol_headers
  INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fs/tracing_path.h
  MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/mmap.o
  MKDIR   /tmp/tmp.DWo9tIFvWU/libapi/fd/
  INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/xyarray.h
  MKDIR   /tmp/tmp.DWo9tIFvWU/libapi/fs/
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/btf.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/zalloc.o
  CC      /tmp/tmp.DWo9tIFvWU/libapi/debug.o
  CC      /tmp/tmp.DWo9tIFvWU/libapi/fd/array.o
  CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/fs.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_common.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_legacy.h
  CC      /tmp/tmp.DWo9tIFvWU/libapi/str_error_r.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_helpers.h
  MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/
  INSTALL libperf_headers
  INSTALL libapi_headers
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_tracing.h
  CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/tracing_path.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_endian.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/xyarray.o
  CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/cgroup.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_core_read.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/skel_internal.h
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_version.h
  CC      /tmp/tmp.DWo9tIFvWU/libperf/lib.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/usdt.bpf.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/hashmap.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/relo_core.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_internal.h
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/help.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/exec-cmd.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/pager.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/parse-options.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/run-command.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/sigchain.o
  CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/subcmd-config.o
  INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_helper_defs.h
  INSTALL libbpf_headers
  GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/bpf_helper_defs.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/btf.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_common.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_legacy.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helpers.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_tracing.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_endian.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_core_read.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/skel_internal.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_version.h
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/usdt.bpf.h
  LD      /tmp/tmp.DWo9tIFvWU/libapi/fd/libapi-in.o
  LD      /tmp/tmp.DWo9tIFvWU/libsymbol/libsymbol-in.o
  AR      /tmp/tmp.DWo9tIFvWU/libsymbol/libsymbol.a
  LD      /tmp/tmp.DWo9tIFvWU/libapi/fs/libapi-in.o
  INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helper_defs.h
  INSTALL libbpf_headers
  LD      /tmp/tmp.DWo9tIFvWU/libapi/libapi-in.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/bpf.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/nlattr.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf_errno.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/str_error.o
  LD      /tmp/tmp.DWo9tIFvWU/libperf/libperf-in.o
  AR      /tmp/tmp.DWo9tIFvWU/libapi/libapi.a
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/netlink.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/bpf_prog_linfo.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf_probes.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/hashmap.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_dump.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/ringbuf.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/strset.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/linker.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/gen_loader.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/relo_core.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/usdt.o
  AR      /tmp/tmp.DWo9tIFvWU/libperf/libperf.a
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/zip.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/elf.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/features.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_iter.o
  CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_relocate.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/nlattr.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_errno.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/str_error.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/netlink.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_probes.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/hashmap.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_dump.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ringbuf.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/strset.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/linker.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/gen_loader.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/relo_core.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/usdt.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/zip.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/elf.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/features.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_iter.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_relocate.o
  LD      /tmp/tmp.DWo9tIFvWU/libsubcmd/libsubcmd-in.o
  AR      /tmp/tmp.DWo9tIFvWU/libsubcmd/libsubcmd.a
  LD      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf-in.o
  LINK    /tmp/tmp.DWo9tIFvWU/libbpf/libbpf.a
  LD      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf-in.o
  LINK    /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/libbpf.a
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/main.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/common.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/json_writer.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/gen.o
  CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/btf.o
  LINK    /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/bpftool
  GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/vmlinux.h
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bpf_prog_profiler.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_leader.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_follower.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_cgroup.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/func_latency.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/off_cpu.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_trace.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/sample_filter.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_top.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bench_uprobe.bpf.o
  CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/augmented_raw_syscalls.bpf.o
  GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/bench_uprobe.skel.h
  GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/func_latency.skel.h
util/bpf_skel/lock_contention.bpf.c:612:28: error: declaration of 'struct bpf_iter__kmem_cache' will not be visible outside of this function [-Werror,-Wvisibility]
  612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
      |                            ^
util/bpf_skel/lock_contention.bpf.c:614:28: error: incomplete definition of type 'struct bpf_iter__kmem_cache'
  614 |         struct kmem_cache *s = ctx->s;
      |                                ~~~^
util/bpf_skel/lock_contention.bpf.c:612:28: note: forward declaration of 'struct bpf_iter__kmem_cache'
  612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
      |                            ^
2 errors generated.
make[4]: *** [Makefile.perf:1248: /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [Makefile.perf:292: sub-make] Error 2
make[2]: *** [Makefile:76: all] Error 2
make[1]: *** [tests/make:344: make_gen_vmlinux_h_O] Error 1
make: *** [Makefile:109: build-test] Error 2
make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'

real	3m43.896s
user	29m30.716s
sys	6m36.609s
⬢ [acme@toolbox perf-tools-next]$ 


 
> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> ---
>  tools/perf/util/bpf_lock_contention.c         | 50 +++++++++++++++++++
>  .../perf/util/bpf_skel/lock_contention.bpf.c  | 28 +++++++++++
>  tools/perf/util/bpf_skel/lock_data.h          | 12 +++++
>  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |  8 +++
>  4 files changed, 98 insertions(+)
> 
> diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
> index 41a1ad08789511c3..558590c3111390fc 100644
> --- a/tools/perf/util/bpf_lock_contention.c
> +++ b/tools/perf/util/bpf_lock_contention.c
> @@ -12,12 +12,59 @@
>  #include <linux/zalloc.h>
>  #include <linux/string.h>
>  #include <bpf/bpf.h>
> +#include <bpf/btf.h>
>  #include <inttypes.h>
>  
>  #include "bpf_skel/lock_contention.skel.h"
>  #include "bpf_skel/lock_data.h"
>  
>  static struct lock_contention_bpf *skel;
> +static bool has_slab_iter;
> +
> +static void check_slab_cache_iter(struct lock_contention *con)
> +{
> +	struct btf *btf = btf__load_vmlinux_btf();
> +	s32 ret;
> +
> +	if (btf == NULL) {
> +		pr_debug("BTF loading failed: %s\n", strerror(errno));
> +		return;
> +	}
> +
> +	ret = btf__find_by_name_kind(btf, "bpf_iter__kmem_cache", BTF_KIND_STRUCT);
> +	if (ret < 0) {
> +		bpf_program__set_autoload(skel->progs.slab_cache_iter, false);
> +		pr_debug("slab cache iterator is not available: %d\n", ret);
> +		goto out;
> +	}
> +
> +	has_slab_iter = true;
> +
> +	bpf_map__set_max_entries(skel->maps.slab_caches, con->map_nr_entries);
> +out:
> +	btf__free(btf);
> +}
> +
> +static void run_slab_cache_iter(void)
> +{
> +	int fd;
> +	char buf[256];
> +
> +	if (!has_slab_iter)
> +		return;
> +
> +	fd = bpf_iter_create(bpf_link__fd(skel->links.slab_cache_iter));
> +	if (fd < 0) {
> +		pr_debug("cannot create slab cache iter: %d\n", fd);
> +		return;
> +	}
> +
> +	/* This will run the bpf program */
> +	while (read(fd, buf, sizeof(buf)) > 0)
> +		continue;
> +
> +	close(fd);
> +}
>  
>  int lock_contention_prepare(struct lock_contention *con)
>  {
> @@ -109,6 +156,8 @@ int lock_contention_prepare(struct lock_contention *con)
>  			skel->rodata->use_cgroup_v2 = 1;
>  	}
>  
> +	check_slab_cache_iter(con);
> +
>  	if (lock_contention_bpf__load(skel) < 0) {
>  		pr_err("Failed to load lock-contention BPF skeleton\n");
>  		return -1;
> @@ -304,6 +353,7 @@ static void account_end_timestamp(struct lock_contention *con)
>  
>  int lock_contention_start(void)
>  {
> +	run_slab_cache_iter();
>  	skel->bss->enabled = 1;
>  	return 0;
>  }
> diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> index 1069bda5d733887f..fd24ccb00faec0ba 100644
> --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> @@ -100,6 +100,13 @@ struct {
>  	__uint(max_entries, 1);
>  } cgroup_filter SEC(".maps");
>  
> +struct {
> +	__uint(type, BPF_MAP_TYPE_HASH);
> +	__uint(key_size, sizeof(long));
> +	__uint(value_size, sizeof(struct slab_cache_data));
> +	__uint(max_entries, 1);
> +} slab_caches SEC(".maps");
> +
>  struct rw_semaphore___old {
>  	struct task_struct *owner;
>  } __attribute__((preserve_access_index));
> @@ -136,6 +143,8 @@ int perf_subsys_id = -1;
>  
>  __u64 end_ts;
>  
> +__u32 slab_cache_id;
> +
>  /* error stat */
>  int task_fail;
>  int stack_fail;
> @@ -563,4 +572,23 @@ int BPF_PROG(end_timestamp)
>  	return 0;
>  }
>  
> +SEC("iter/kmem_cache")
> +int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> +{
> +	struct kmem_cache *s = ctx->s;
> +	struct slab_cache_data d;
> +
> +	if (s == NULL)
> +		return 0;
> +
> +	d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT;
> +	bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name);
> +
> +	if (d.id >= LCB_F_SLAB_ID_END)
> +		return 0;
> +
> +	bpf_map_update_elem(&slab_caches, &s, &d, BPF_NOEXIST);
> +	return 0;
> +}
> +
>  char LICENSE[] SEC("license") = "Dual BSD/GPL";
> diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
> index 4f0aae5483745dfa..c15f734d7fc4aecb 100644
> --- a/tools/perf/util/bpf_skel/lock_data.h
> +++ b/tools/perf/util/bpf_skel/lock_data.h
> @@ -32,9 +32,16 @@ struct contention_task_data {
>  #define LCD_F_MMAP_LOCK		(1U << 31)
>  #define LCD_F_SIGHAND_LOCK	(1U << 30)
>  
> +#define LCB_F_SLAB_ID_SHIFT	16
> +#define LCB_F_SLAB_ID_START	(1U << 16)
> +#define LCB_F_SLAB_ID_END	(1U << 26)
> +#define LCB_F_SLAB_ID_MASK	0x03FF0000U
> +
>  #define LCB_F_TYPE_MAX		(1U << 7)
>  #define LCB_F_TYPE_MASK		0x0000007FU
>  
> +#define SLAB_NAME_MAX  28
> +
>  struct contention_data {
>  	u64 total_time;
>  	u64 min_time;
> @@ -55,4 +62,9 @@ enum lock_class_sym {
>  	LOCK_CLASS_RQLOCK,
>  };
>  
> +struct slab_cache_data {
> +	u32 id;
> +	char name[SLAB_NAME_MAX];
> +};
> +
>  #endif /* UTIL_BPF_SKEL_LOCK_DATA_H */
> diff --git a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> index 4dcad7b682bdee9c..7b81d3173917fdb5 100644
> --- a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> +++ b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> @@ -195,4 +195,12 @@ struct bpf_perf_event_data_kern {
>   */
>  struct rq {};
>  
> +struct kmem_cache {
> +	const char *name;
> +} __attribute__((preserve_access_index));
> +
> +struct bpf_iter__kmem_cache {
> +	struct kmem_cache *s;
> +} __attribute__((preserve_access_index));
> +
>  #endif // __VMLINUX_H
> -- 
> 2.47.0.277.g8800431eea-goog

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-12-09 16:36   ` Arnaldo Carvalho de Melo
@ 2024-12-09 16:38     ` Arnaldo Carvalho de Melo
  2024-12-09 20:23       ` Arnaldo Carvalho de Melo
  2024-12-09 22:16       ` Namhyung Kim
  0 siblings, 2 replies; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2024-12-09 16:38 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra,
	Ingo Molnar, LKML, linux-perf-users, Andrii Nakryiko, Song Liu,
	bpf, Stephane Eranian, Vlastimil Babka, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On Mon, Dec 09, 2024 at 01:36:52PM -0300, Arnaldo Carvalho de Melo wrote:
> On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> > Recently the kernel got the kmem_cache iterator to traverse metadata of
> > slab objects.  This can be used to symbolize dynamic locks in a slab.
> > 
> > The new slab_caches hash map will have the pointer of the kmem_cache as
> > a key and save the name and a id.  The id will be saved in the flags
> > part of the lock.
> 
> Trying to fix this 

So you have that struct in tools/perf/util/bpf_skel/vmlinux/vmlinux.h,
but then, this kernel is old and doesn't have the kmem_cache iterator,
so using the generated vmlinux.h will fail the build.

- Arnaldo
 
> cd . && make GEN_VMLINUX_H=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j28 O=/tmp/tmp.DWo9tIFvWU DESTDIR=/tmp/tmp.ex3iljqLBT
>   BUILD:   Doing 'make -j28' parallel build
> Warning: Kernel ABI header differences:
>   diff -u tools/include/uapi/drm/drm.h include/uapi/drm/drm.h
>   diff -u tools/include/uapi/linux/kvm.h include/uapi/linux/kvm.h
>   diff -u tools/include/uapi/linux/perf_event.h include/uapi/linux/perf_event.h
>   diff -u tools/arch/x86/include/asm/cpufeatures.h arch/x86/include/asm/cpufeatures.h
>   diff -u tools/arch/x86/include/uapi/asm/kvm.h arch/x86/include/uapi/asm/kvm.h
>   diff -u tools/arch/arm64/include/uapi/asm/kvm.h arch/arm64/include/uapi/asm/kvm.h
>   diff -u tools/arch/arm64/include/uapi/asm/unistd.h arch/arm64/include/uapi/asm/unistd.h
>   diff -u tools/include/uapi/asm-generic/unistd.h include/uapi/asm-generic/unistd.h
>   diff -u tools/include/uapi/asm-generic/mman.h include/uapi/asm-generic/mman.h
>   diff -u tools/perf/arch/x86/entry/syscalls/syscall_32.tbl arch/x86/entry/syscalls/syscall_32.tbl
>   diff -u tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
>   diff -u tools/perf/arch/powerpc/entry/syscalls/syscall.tbl arch/powerpc/kernel/syscalls/syscall.tbl
>   diff -u tools/perf/arch/s390/entry/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl
>   diff -u tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl arch/mips/kernel/syscalls/syscall_n64.tbl
>   diff -u tools/perf/trace/beauty/include/uapi/linux/fcntl.h include/uapi/linux/fcntl.h
>   diff -u tools/perf/trace/beauty/include/uapi/linux/mount.h include/uapi/linux/mount.h
>   diff -u tools/perf/trace/beauty/include/uapi/linux/prctl.h include/uapi/linux/prctl.h
> Makefile.config:989: No libllvm 13+ found, slower source file resolution, please install llvm-devel/llvm-dev
> Makefile.config:1171: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel
> 
>   GEN     /tmp/tmp.DWo9tIFvWU/common-cmds.h
>   CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v0.o
>   CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v2.o
>   CC      /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-show-cycles.o
>   GEN     /tmp/tmp.DWo9tIFvWU/arch/arm64/include/generated/asm/sysreg-defs.h
>   LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v2.so
>   LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-show-cycles.so
>   LINK    /tmp/tmp.DWo9tIFvWU/dlfilters/dlfilter-test-api-v0.so
>   PERF_VERSION = 6.13.rc1.g61c6ae4ddd41
>   GEN     perf-iostat
>   GEN     perf-archive
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/exec-cmd.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/help.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/pager.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/parse-options.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsubcmd/include/subcmd/run-command.h
>   INSTALL libsubcmd_headers
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/bpf_perf.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/core.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/cpumap.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/threadmap.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/evlist.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/evsel.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/event.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/perf/mmap.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/core.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/cpumap.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/evlist.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/cpu.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/cpumap.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libsymbol/include/symbol/kallsyms.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/evsel.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/io.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/debug.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/lib.h
>   CC      /tmp/tmp.DWo9tIFvWU/libsymbol/kallsyms.o
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/threadmap.o
>   GEN     /tmp/tmp.DWo9tIFvWU/libbpf/bpf_helper_defs.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/mmap.h
>   MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/evsel.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/rc_check.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fd/array.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/threadmap.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/evlist.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fs/fs.h
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/cpu.o
>   INSTALL libsymbol_headers
>   INSTALL /tmp/tmp.DWo9tIFvWU/libapi/include/api/fs/tracing_path.h
>   MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/mmap.o
>   MKDIR   /tmp/tmp.DWo9tIFvWU/libapi/fd/
>   INSTALL /tmp/tmp.DWo9tIFvWU/libperf/include/internal/xyarray.h
>   MKDIR   /tmp/tmp.DWo9tIFvWU/libapi/fs/
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/btf.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/zalloc.o
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/debug.o
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/fd/array.o
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/fs.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_common.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_legacy.h
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/str_error_r.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_helpers.h
>   MKDIR   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/
>   INSTALL libperf_headers
>   INSTALL libapi_headers
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_tracing.h
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/tracing_path.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_endian.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/xyarray.o
>   CC      /tmp/tmp.DWo9tIFvWU/libapi/fs/cgroup.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_core_read.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/skel_internal.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/libbpf_version.h
>   CC      /tmp/tmp.DWo9tIFvWU/libperf/lib.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/usdt.bpf.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/hashmap.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/relo_core.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_internal.h
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/help.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/exec-cmd.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/pager.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/parse-options.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/run-command.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/sigchain.o
>   CC      /tmp/tmp.DWo9tIFvWU/libsubcmd/subcmd-config.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/libbpf/include/bpf/bpf_helper_defs.h
>   INSTALL libbpf_headers
>   GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/bpf_helper_defs.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/btf.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_common.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_legacy.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helpers.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_tracing.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_endian.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_core_read.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/skel_internal.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_version.h
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/usdt.bpf.h
>   LD      /tmp/tmp.DWo9tIFvWU/libapi/fd/libapi-in.o
>   LD      /tmp/tmp.DWo9tIFvWU/libsymbol/libsymbol-in.o
>   AR      /tmp/tmp.DWo9tIFvWU/libsymbol/libsymbol.a
>   LD      /tmp/tmp.DWo9tIFvWU/libapi/fs/libapi-in.o
>   INSTALL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helper_defs.h
>   INSTALL libbpf_headers
>   LD      /tmp/tmp.DWo9tIFvWU/libapi/libapi-in.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/bpf.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/nlattr.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf_errno.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/str_error.o
>   LD      /tmp/tmp.DWo9tIFvWU/libperf/libperf-in.o
>   AR      /tmp/tmp.DWo9tIFvWU/libapi/libapi.a
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/netlink.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/bpf_prog_linfo.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf_probes.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/hashmap.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_dump.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/ringbuf.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/strset.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/linker.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/gen_loader.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/relo_core.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/usdt.o
>   AR      /tmp/tmp.DWo9tIFvWU/libperf/libperf.a
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/zip.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/elf.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/features.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_iter.o
>   CC      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/btf_relocate.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/nlattr.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_errno.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/str_error.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/netlink.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_probes.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/hashmap.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_dump.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ringbuf.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/strset.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/linker.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/gen_loader.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/relo_core.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/usdt.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/zip.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/elf.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/features.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_iter.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_relocate.o
>   LD      /tmp/tmp.DWo9tIFvWU/libsubcmd/libsubcmd-in.o
>   AR      /tmp/tmp.DWo9tIFvWU/libsubcmd/libsubcmd.a
>   LD      /tmp/tmp.DWo9tIFvWU/libbpf/staticobjs/libbpf-in.o
>   LINK    /tmp/tmp.DWo9tIFvWU/libbpf/libbpf.a
>   LD      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf-in.o
>   LINK    /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/libbpf/libbpf.a
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/main.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/common.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/json_writer.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/gen.o
>   CC      /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/btf.o
>   LINK    /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bootstrap/bpftool
>   GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/vmlinux.h
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bpf_prog_profiler.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_leader.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_follower.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_cgroup.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/func_latency.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/off_cpu.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_trace.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/sample_filter.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_top.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bench_uprobe.bpf.o
>   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/augmented_raw_syscalls.bpf.o
>   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/bench_uprobe.skel.h
>   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/func_latency.skel.h
> util/bpf_skel/lock_contention.bpf.c:612:28: error: declaration of 'struct bpf_iter__kmem_cache' will not be visible outside of this function [-Werror,-Wvisibility]
>   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
>       |                            ^
> util/bpf_skel/lock_contention.bpf.c:614:28: error: incomplete definition of type 'struct bpf_iter__kmem_cache'
>   614 |         struct kmem_cache *s = ctx->s;
>       |                                ~~~^
> util/bpf_skel/lock_contention.bpf.c:612:28: note: forward declaration of 'struct bpf_iter__kmem_cache'
>   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
>       |                            ^
> 2 errors generated.
> make[4]: *** [Makefile.perf:1248: /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o] Error 1
> make[4]: *** Waiting for unfinished jobs....
> make[3]: *** [Makefile.perf:292: sub-make] Error 2
> make[2]: *** [Makefile:76: all] Error 2
> make[1]: *** [tests/make:344: make_gen_vmlinux_h_O] Error 1
> make: *** [Makefile:109: build-test] Error 2
> make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'
> 
> real	3m43.896s
> user	29m30.716s
> sys	6m36.609s
> ⬢ [acme@toolbox perf-tools-next]$ 
> 
> 
>  
> > Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> > ---
> >  tools/perf/util/bpf_lock_contention.c         | 50 +++++++++++++++++++
> >  .../perf/util/bpf_skel/lock_contention.bpf.c  | 28 +++++++++++
> >  tools/perf/util/bpf_skel/lock_data.h          | 12 +++++
> >  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |  8 +++
> >  4 files changed, 98 insertions(+)
> > 
> > diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
> > index 41a1ad08789511c3..558590c3111390fc 100644
> > --- a/tools/perf/util/bpf_lock_contention.c
> > +++ b/tools/perf/util/bpf_lock_contention.c
> > @@ -12,12 +12,59 @@
> >  #include <linux/zalloc.h>
> >  #include <linux/string.h>
> >  #include <bpf/bpf.h>
> > +#include <bpf/btf.h>
> >  #include <inttypes.h>
> >  
> >  #include "bpf_skel/lock_contention.skel.h"
> >  #include "bpf_skel/lock_data.h"
> >  
> >  static struct lock_contention_bpf *skel;
> > +static bool has_slab_iter;
> > +
> > +static void check_slab_cache_iter(struct lock_contention *con)
> > +{
> > +	struct btf *btf = btf__load_vmlinux_btf();
> > +	s32 ret;
> > +
> > +	if (btf == NULL) {
> > +		pr_debug("BTF loading failed: %s\n", strerror(errno));
> > +		return;
> > +	}
> > +
> > +	ret = btf__find_by_name_kind(btf, "bpf_iter__kmem_cache", BTF_KIND_STRUCT);
> > +	if (ret < 0) {
> > +		bpf_program__set_autoload(skel->progs.slab_cache_iter, false);
> > +		pr_debug("slab cache iterator is not available: %d\n", ret);
> > +		goto out;
> > +	}
> > +
> > +	has_slab_iter = true;
> > +
> > +	bpf_map__set_max_entries(skel->maps.slab_caches, con->map_nr_entries);
> > +out:
> > +	btf__free(btf);
> > +}
> > +
> > +static void run_slab_cache_iter(void)
> > +{
> > +	int fd;
> > +	char buf[256];
> > +
> > +	if (!has_slab_iter)
> > +		return;
> > +
> > +	fd = bpf_iter_create(bpf_link__fd(skel->links.slab_cache_iter));
> > +	if (fd < 0) {
> > +		pr_debug("cannot create slab cache iter: %d\n", fd);
> > +		return;
> > +	}
> > +
> > +	/* This will run the bpf program */
> > +	while (read(fd, buf, sizeof(buf)) > 0)
> > +		continue;
> > +
> > +	close(fd);
> > +}
> >  
> >  int lock_contention_prepare(struct lock_contention *con)
> >  {
> > @@ -109,6 +156,8 @@ int lock_contention_prepare(struct lock_contention *con)
> >  			skel->rodata->use_cgroup_v2 = 1;
> >  	}
> >  
> > +	check_slab_cache_iter(con);
> > +
> >  	if (lock_contention_bpf__load(skel) < 0) {
> >  		pr_err("Failed to load lock-contention BPF skeleton\n");
> >  		return -1;
> > @@ -304,6 +353,7 @@ static void account_end_timestamp(struct lock_contention *con)
> >  
> >  int lock_contention_start(void)
> >  {
> > +	run_slab_cache_iter();
> >  	skel->bss->enabled = 1;
> >  	return 0;
> >  }
> > diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > index 1069bda5d733887f..fd24ccb00faec0ba 100644
> > --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > @@ -100,6 +100,13 @@ struct {
> >  	__uint(max_entries, 1);
> >  } cgroup_filter SEC(".maps");
> >  
> > +struct {
> > +	__uint(type, BPF_MAP_TYPE_HASH);
> > +	__uint(key_size, sizeof(long));
> > +	__uint(value_size, sizeof(struct slab_cache_data));
> > +	__uint(max_entries, 1);
> > +} slab_caches SEC(".maps");
> > +
> >  struct rw_semaphore___old {
> >  	struct task_struct *owner;
> >  } __attribute__((preserve_access_index));
> > @@ -136,6 +143,8 @@ int perf_subsys_id = -1;
> >  
> >  __u64 end_ts;
> >  
> > +__u32 slab_cache_id;
> > +
> >  /* error stat */
> >  int task_fail;
> >  int stack_fail;
> > @@ -563,4 +572,23 @@ int BPF_PROG(end_timestamp)
> >  	return 0;
> >  }
> >  
> > +SEC("iter/kmem_cache")
> > +int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> > +{
> > +	struct kmem_cache *s = ctx->s;
> > +	struct slab_cache_data d;
> > +
> > +	if (s == NULL)
> > +		return 0;
> > +
> > +	d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT;
> > +	bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name);
> > +
> > +	if (d.id >= LCB_F_SLAB_ID_END)
> > +		return 0;
> > +
> > +	bpf_map_update_elem(&slab_caches, &s, &d, BPF_NOEXIST);
> > +	return 0;
> > +}
> > +
> >  char LICENSE[] SEC("license") = "Dual BSD/GPL";
> > diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
> > index 4f0aae5483745dfa..c15f734d7fc4aecb 100644
> > --- a/tools/perf/util/bpf_skel/lock_data.h
> > +++ b/tools/perf/util/bpf_skel/lock_data.h
> > @@ -32,9 +32,16 @@ struct contention_task_data {
> >  #define LCD_F_MMAP_LOCK		(1U << 31)
> >  #define LCD_F_SIGHAND_LOCK	(1U << 30)
> >  
> > +#define LCB_F_SLAB_ID_SHIFT	16
> > +#define LCB_F_SLAB_ID_START	(1U << 16)
> > +#define LCB_F_SLAB_ID_END	(1U << 26)
> > +#define LCB_F_SLAB_ID_MASK	0x03FF0000U
> > +
> >  #define LCB_F_TYPE_MAX		(1U << 7)
> >  #define LCB_F_TYPE_MASK		0x0000007FU
> >  
> > +#define SLAB_NAME_MAX  28
> > +
> >  struct contention_data {
> >  	u64 total_time;
> >  	u64 min_time;
> > @@ -55,4 +62,9 @@ enum lock_class_sym {
> >  	LOCK_CLASS_RQLOCK,
> >  };
> >  
> > +struct slab_cache_data {
> > +	u32 id;
> > +	char name[SLAB_NAME_MAX];
> > +};
> > +
> >  #endif /* UTIL_BPF_SKEL_LOCK_DATA_H */
> > diff --git a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > index 4dcad7b682bdee9c..7b81d3173917fdb5 100644
> > --- a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > +++ b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > @@ -195,4 +195,12 @@ struct bpf_perf_event_data_kern {
> >   */
> >  struct rq {};
> >  
> > +struct kmem_cache {
> > +	const char *name;
> > +} __attribute__((preserve_access_index));
> > +
> > +struct bpf_iter__kmem_cache {
> > +	struct kmem_cache *s;
> > +} __attribute__((preserve_access_index));
> > +
> >  #endif // __VMLINUX_H
> > -- 
> > 2.47.0.277.g8800431eea-goog

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-12-09 16:38     ` Arnaldo Carvalho de Melo
@ 2024-12-09 20:23       ` Arnaldo Carvalho de Melo
  2024-12-09 23:00         ` Andrii Nakryiko
  2024-12-09 22:16       ` Namhyung Kim
  1 sibling, 1 reply; 19+ messages in thread
From: Arnaldo Carvalho de Melo @ 2024-12-09 20:23 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra,
	Ingo Molnar, LKML, linux-perf-users, Andrii Nakryiko, Song Liu,
	bpf, Stephane Eranian, Vlastimil Babka, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On Mon, Dec 09, 2024 at 01:38:39PM -0300, Arnaldo Carvalho de Melo wrote:
> On Mon, Dec 09, 2024 at 01:36:52PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> > > Recently the kernel got the kmem_cache iterator to traverse metadata of
> > > slab objects.  This can be used to symbolize dynamic locks in a slab.

> > > The new slab_caches hash map will have the pointer of the kmem_cache as
> > > a key and save the name and a id.  The id will be saved in the flags
> > > part of the lock.

> > Trying to fix this 
> 
> So you have that struct in tools/perf/util/bpf_skel/vmlinux/vmlinux.h,
> but then, this kernel is old and doesn't have the kmem_cache iterator,
> so using the generated vmlinux.h will fail the build.

I tried passing the right offset to the iterator so as not to try to use
a type that isn't in vmlinux.h generated from the old kernel BTF:

+++ b/tools/perf/util/bpf_lock_contention.c
@@ -52,7 +52,7 @@ static void check_slab_cache_iter(struct lock_contention *con)
                pr_debug("slab cache iterator is not available: %d\n", ret);
                goto out;
        } else {
-               const struct btf_member *s = __btf_type__find_member_by_name(btf, ret, "s");
+               const struct btf_member *s = __btf_type__find_unnamed_union_with_member_by_name(btf, ret, "s");
 
                if (s == NULL) {
                        skel->rodata->slab_cache_iter_member_offset = -1;
@@ -60,7 +60,9 @@ static void check_slab_cache_iter(struct lock_contention *con)
                        goto out;
                }
 
                skel->rodata->slab_cache_iter_member_offset = s->offset / 8; // bits -> bytes
+               pr_debug("slab cache iterator kmem_cache pointer offset: %d\n",
+                        skel->rodata->slab_cache_iter_member_offset);
        }


but the verifier doesn't like that:

; struct kmem_cache *s = slab_cache_iter_member_offset < 0 ? NULL : @ lock_contention.bpf.c:615
12: (7b) *(u64 *)(r10 -8) = r2        ; R2_w=ctx(off=8) R10=fp0 fp-8_w=ctx(off=8)
; if (s == NULL) @ lock_contention.bpf.c:619
13: (15) if r1 == 0x0 goto pc+22      ; R1=ctx()
; d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT; @ lock_contention.bpf.c:622
14: (18) r1 = 0xffffc14bcde3a014      ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20)
16: (61) r3 = *(u32 *)(r1 +0)         ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20) R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
17: (07) r3 += 1                      ; R3_w=scalar(smin=umin=1,smax=umax=0x100000000,var_off=(0x0; 0x1ffffffff))
18: (63) *(u32 *)(r1 +0) = r3         ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20) R3_w=scalar(smin=umin=1,smax=umax=0x100000000,var_off=(0x0; 0x1ffffffff))
19: (67) r3 <<= 16                    ; R3_w=scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000))
20: (63) *(u32 *)(r10 -40) = r3       ; R3_w=scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000)) R10=fp0 fp-40=????scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000))
; bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name); @ lock_contention.bpf.c:623
21: (79) r3 = *(u64 *)(r2 +96)
dereference of modified ctx ptr R2 off=8 disallowed
processed 19 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: prog 'slab_cache_iter': failed to load: -EACCES
libbpf: failed to load object 'lock_contention_bpf'
libbpf: failed to load BPF skeleton 'lock_contention_bpf': -EACCES
Failed to load lock-contention BPF skeleton
lock contention BPF setup failed
root@number:~# 

and additionally the type is not like the one you added to the barebones
vmlinux.h:

⬢ [acme@toolbox perf-tools-next]$ git show d82e2e170d1c756b | grep 'struct bpf_iter__kmem_cache {' -A3
+struct bpf_iter__kmem_cache {
+	struct kmem_cache *s;
+} __attribute__((preserve_access_index));
+
⬢ [acme@toolbox perf-tools-next]$

But:

⬢ [acme@toolbox perf-tools-next]$ uname -a
Linux toolbox 6.13.0-rc2 #1 SMP PREEMPT_DYNAMIC Mon Dec  9 12:33:35 -03 2024 x86_64 GNU/Linux
⬢ [acme@toolbox perf-tools-next]$ pahole bpf_iter__kmem_cache
struct bpf_iter__kmem_cache {
	union {
		struct bpf_iter_meta * meta;             /*     0     8 */
	};                                               /*     0     8 */
	union {
		struct kmem_cache * s;                   /*     8     8 */
	};                                               /*     8     8 */

	/* size: 16, cachelines: 1, members: 2 */
	/* last cacheline: 16 bytes */
};

⬢ [acme@toolbox perf-tools-next]$

Do CO-RE handle this?

- Arnaldo

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-12-09 16:38     ` Arnaldo Carvalho de Melo
  2024-12-09 20:23       ` Arnaldo Carvalho de Melo
@ 2024-12-09 22:16       ` Namhyung Kim
  2024-12-09 22:23         ` Ian Rogers
  1 sibling, 1 reply; 19+ messages in thread
From: Namhyung Kim @ 2024-12-09 22:16 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter, Peter Zijlstra,
	Ingo Molnar, LKML, linux-perf-users, Andrii Nakryiko, Song Liu,
	bpf, Stephane Eranian, Vlastimil Babka, Roman Gushchin,
	Hyeonggon Yoo, Kees Cook

On Mon, Dec 09, 2024 at 01:38:39PM -0300, Arnaldo Carvalho de Melo wrote:
> On Mon, Dec 09, 2024 at 01:36:52PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> > > Recently the kernel got the kmem_cache iterator to traverse metadata of
> > > slab objects.  This can be used to symbolize dynamic locks in a slab.
> > > 
> > > The new slab_caches hash map will have the pointer of the kmem_cache as
> > > a key and save the name and a id.  The id will be saved in the flags
> > > part of the lock.
> > 
> > Trying to fix this 
> 
> So you have that struct in tools/perf/util/bpf_skel/vmlinux/vmlinux.h,
> but then, this kernel is old and doesn't have the kmem_cache iterator,
> so using the generated vmlinux.h will fail the build.

Thanks for checking this.  I think we handle compatibility issues by
checking BTF at runtime but this is a build-time issue. :(

I wonder if it's really needed to generate vmlinux.h for perf.  Can we
simply use the minimal vmlinux.h always?

Thanks,
Namhyung

>  
> > cd . && make GEN_VMLINUX_H=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j28 O=/tmp/tmp.DWo9tIFvWU DESTDIR=/tmp/tmp.ex3iljqLBT
> >   BUILD:   Doing 'make -j28' parallel build
[...]
> >   GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/vmlinux.h
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bpf_prog_profiler.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_leader.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_follower.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_cgroup.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/func_latency.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/off_cpu.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_trace.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/sample_filter.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_top.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bench_uprobe.bpf.o
> >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/augmented_raw_syscalls.bpf.o
> >   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/bench_uprobe.skel.h
> >   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/func_latency.skel.h
> > util/bpf_skel/lock_contention.bpf.c:612:28: error: declaration of 'struct bpf_iter__kmem_cache' will not be visible outside of this function [-Werror,-Wvisibility]
> >   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> >       |                            ^
> > util/bpf_skel/lock_contention.bpf.c:614:28: error: incomplete definition of type 'struct bpf_iter__kmem_cache'
> >   614 |         struct kmem_cache *s = ctx->s;
> >       |                                ~~~^
> > util/bpf_skel/lock_contention.bpf.c:612:28: note: forward declaration of 'struct bpf_iter__kmem_cache'
> >   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> >       |                            ^
> > 2 errors generated.
> > make[4]: *** [Makefile.perf:1248: /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o] Error 1
> > make[4]: *** Waiting for unfinished jobs....
> > make[3]: *** [Makefile.perf:292: sub-make] Error 2
> > make[2]: *** [Makefile:76: all] Error 2
> > make[1]: *** [tests/make:344: make_gen_vmlinux_h_O] Error 1
> > make: *** [Makefile:109: build-test] Error 2
> > make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'
> > 
> > real	3m43.896s
> > user	29m30.716s
> > sys	6m36.609s
> > ⬢ [acme@toolbox perf-tools-next]$ 
> > 
> > 
> >  
> > > Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> > > ---
> > >  tools/perf/util/bpf_lock_contention.c         | 50 +++++++++++++++++++
> > >  .../perf/util/bpf_skel/lock_contention.bpf.c  | 28 +++++++++++
> > >  tools/perf/util/bpf_skel/lock_data.h          | 12 +++++
> > >  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |  8 +++
> > >  4 files changed, 98 insertions(+)
> > > 
> > > diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
> > > index 41a1ad08789511c3..558590c3111390fc 100644
> > > --- a/tools/perf/util/bpf_lock_contention.c
> > > +++ b/tools/perf/util/bpf_lock_contention.c
> > > @@ -12,12 +12,59 @@
> > >  #include <linux/zalloc.h>
> > >  #include <linux/string.h>
> > >  #include <bpf/bpf.h>
> > > +#include <bpf/btf.h>
> > >  #include <inttypes.h>
> > >  
> > >  #include "bpf_skel/lock_contention.skel.h"
> > >  #include "bpf_skel/lock_data.h"
> > >  
> > >  static struct lock_contention_bpf *skel;
> > > +static bool has_slab_iter;
> > > +
> > > +static void check_slab_cache_iter(struct lock_contention *con)
> > > +{
> > > +	struct btf *btf = btf__load_vmlinux_btf();
> > > +	s32 ret;
> > > +
> > > +	if (btf == NULL) {
> > > +		pr_debug("BTF loading failed: %s\n", strerror(errno));
> > > +		return;
> > > +	}
> > > +
> > > +	ret = btf__find_by_name_kind(btf, "bpf_iter__kmem_cache", BTF_KIND_STRUCT);
> > > +	if (ret < 0) {
> > > +		bpf_program__set_autoload(skel->progs.slab_cache_iter, false);
> > > +		pr_debug("slab cache iterator is not available: %d\n", ret);
> > > +		goto out;
> > > +	}
> > > +
> > > +	has_slab_iter = true;
> > > +
> > > +	bpf_map__set_max_entries(skel->maps.slab_caches, con->map_nr_entries);
> > > +out:
> > > +	btf__free(btf);
> > > +}
> > > +
> > > +static void run_slab_cache_iter(void)
> > > +{
> > > +	int fd;
> > > +	char buf[256];
> > > +
> > > +	if (!has_slab_iter)
> > > +		return;
> > > +
> > > +	fd = bpf_iter_create(bpf_link__fd(skel->links.slab_cache_iter));
> > > +	if (fd < 0) {
> > > +		pr_debug("cannot create slab cache iter: %d\n", fd);
> > > +		return;
> > > +	}
> > > +
> > > +	/* This will run the bpf program */
> > > +	while (read(fd, buf, sizeof(buf)) > 0)
> > > +		continue;
> > > +
> > > +	close(fd);
> > > +}
> > >  
> > >  int lock_contention_prepare(struct lock_contention *con)
> > >  {
> > > @@ -109,6 +156,8 @@ int lock_contention_prepare(struct lock_contention *con)
> > >  			skel->rodata->use_cgroup_v2 = 1;
> > >  	}
> > >  
> > > +	check_slab_cache_iter(con);
> > > +
> > >  	if (lock_contention_bpf__load(skel) < 0) {
> > >  		pr_err("Failed to load lock-contention BPF skeleton\n");
> > >  		return -1;
> > > @@ -304,6 +353,7 @@ static void account_end_timestamp(struct lock_contention *con)
> > >  
> > >  int lock_contention_start(void)
> > >  {
> > > +	run_slab_cache_iter();
> > >  	skel->bss->enabled = 1;
> > >  	return 0;
> > >  }
> > > diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > index 1069bda5d733887f..fd24ccb00faec0ba 100644
> > > --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > @@ -100,6 +100,13 @@ struct {
> > >  	__uint(max_entries, 1);
> > >  } cgroup_filter SEC(".maps");
> > >  
> > > +struct {
> > > +	__uint(type, BPF_MAP_TYPE_HASH);
> > > +	__uint(key_size, sizeof(long));
> > > +	__uint(value_size, sizeof(struct slab_cache_data));
> > > +	__uint(max_entries, 1);
> > > +} slab_caches SEC(".maps");
> > > +
> > >  struct rw_semaphore___old {
> > >  	struct task_struct *owner;
> > >  } __attribute__((preserve_access_index));
> > > @@ -136,6 +143,8 @@ int perf_subsys_id = -1;
> > >  
> > >  __u64 end_ts;
> > >  
> > > +__u32 slab_cache_id;
> > > +
> > >  /* error stat */
> > >  int task_fail;
> > >  int stack_fail;
> > > @@ -563,4 +572,23 @@ int BPF_PROG(end_timestamp)
> > >  	return 0;
> > >  }
> > >  
> > > +SEC("iter/kmem_cache")
> > > +int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> > > +{
> > > +	struct kmem_cache *s = ctx->s;
> > > +	struct slab_cache_data d;
> > > +
> > > +	if (s == NULL)
> > > +		return 0;
> > > +
> > > +	d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT;
> > > +	bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name);
> > > +
> > > +	if (d.id >= LCB_F_SLAB_ID_END)
> > > +		return 0;
> > > +
> > > +	bpf_map_update_elem(&slab_caches, &s, &d, BPF_NOEXIST);
> > > +	return 0;
> > > +}
> > > +
> > >  char LICENSE[] SEC("license") = "Dual BSD/GPL";
> > > diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
> > > index 4f0aae5483745dfa..c15f734d7fc4aecb 100644
> > > --- a/tools/perf/util/bpf_skel/lock_data.h
> > > +++ b/tools/perf/util/bpf_skel/lock_data.h
> > > @@ -32,9 +32,16 @@ struct contention_task_data {
> > >  #define LCD_F_MMAP_LOCK		(1U << 31)
> > >  #define LCD_F_SIGHAND_LOCK	(1U << 30)
> > >  
> > > +#define LCB_F_SLAB_ID_SHIFT	16
> > > +#define LCB_F_SLAB_ID_START	(1U << 16)
> > > +#define LCB_F_SLAB_ID_END	(1U << 26)
> > > +#define LCB_F_SLAB_ID_MASK	0x03FF0000U
> > > +
> > >  #define LCB_F_TYPE_MAX		(1U << 7)
> > >  #define LCB_F_TYPE_MASK		0x0000007FU
> > >  
> > > +#define SLAB_NAME_MAX  28
> > > +
> > >  struct contention_data {
> > >  	u64 total_time;
> > >  	u64 min_time;
> > > @@ -55,4 +62,9 @@ enum lock_class_sym {
> > >  	LOCK_CLASS_RQLOCK,
> > >  };
> > >  
> > > +struct slab_cache_data {
> > > +	u32 id;
> > > +	char name[SLAB_NAME_MAX];
> > > +};
> > > +
> > >  #endif /* UTIL_BPF_SKEL_LOCK_DATA_H */
> > > diff --git a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > index 4dcad7b682bdee9c..7b81d3173917fdb5 100644
> > > --- a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > +++ b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > @@ -195,4 +195,12 @@ struct bpf_perf_event_data_kern {
> > >   */
> > >  struct rq {};
> > >  
> > > +struct kmem_cache {
> > > +	const char *name;
> > > +} __attribute__((preserve_access_index));
> > > +
> > > +struct bpf_iter__kmem_cache {
> > > +	struct kmem_cache *s;
> > > +} __attribute__((preserve_access_index));
> > > +
> > >  #endif // __VMLINUX_H
> > > -- 
> > > 2.47.0.277.g8800431eea-goog

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-12-09 22:16       ` Namhyung Kim
@ 2024-12-09 22:23         ` Ian Rogers
  0 siblings, 0 replies; 19+ messages in thread
From: Ian Rogers @ 2024-12-09 22:23 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Vlastimil Babka,
	Roman Gushchin, Hyeonggon Yoo, Kees Cook

On Mon, Dec 9, 2024 at 2:16 PM Namhyung Kim <namhyung@kernel.org> wrote:
>
> On Mon, Dec 09, 2024 at 01:38:39PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Mon, Dec 09, 2024 at 01:36:52PM -0300, Arnaldo Carvalho de Melo wrote:
> > > On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> > > > Recently the kernel got the kmem_cache iterator to traverse metadata of
> > > > slab objects.  This can be used to symbolize dynamic locks in a slab.
> > > >
> > > > The new slab_caches hash map will have the pointer of the kmem_cache as
> > > > a key and save the name and a id.  The id will be saved in the flags
> > > > part of the lock.
> > >
> > > Trying to fix this
> >
> > So you have that struct in tools/perf/util/bpf_skel/vmlinux/vmlinux.h,
> > but then, this kernel is old and doesn't have the kmem_cache iterator,
> > so using the generated vmlinux.h will fail the build.
>
> Thanks for checking this.  I think we handle compatibility issues by
> checking BTF at runtime but this is a build-time issue. :(
>
> I wonder if it's really needed to generate vmlinux.h for perf.  Can we
> simply use the minimal vmlinux.h always?

Agreed, it shouldn't be necessary. There are certain compilation
errors that will happen with a generated one that can't happen with
the minimal. They could be indicative of bugs, like a renamed struct.

Thanks,
Ian

> >
> > > cd . && make GEN_VMLINUX_H=1 FEATURES_DUMP=/home/acme/git/perf-tools-next/tools/perf/BUILD_TEST_FEATURE_DUMP -j28 O=/tmp/tmp.DWo9tIFvWU DESTDIR=/tmp/tmp.ex3iljqLBT
> > >   BUILD:   Doing 'make -j28' parallel build
> [...]
> > >   GEN     /tmp/tmp.DWo9tIFvWU/util/bpf_skel/vmlinux.h
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bpf_prog_profiler.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_leader.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_follower.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bperf_cgroup.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/func_latency.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/off_cpu.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_trace.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/sample_filter.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/kwork_top.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/bench_uprobe.bpf.o
> > >   CLANG   /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/augmented_raw_syscalls.bpf.o
> > >   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/bench_uprobe.skel.h
> > >   GENSKEL /tmp/tmp.DWo9tIFvWU/util/bpf_skel/func_latency.skel.h
> > > util/bpf_skel/lock_contention.bpf.c:612:28: error: declaration of 'struct bpf_iter__kmem_cache' will not be visible outside of this function [-Werror,-Wvisibility]
> > >   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> > >       |                            ^
> > > util/bpf_skel/lock_contention.bpf.c:614:28: error: incomplete definition of type 'struct bpf_iter__kmem_cache'
> > >   614 |         struct kmem_cache *s = ctx->s;
> > >       |                                ~~~^
> > > util/bpf_skel/lock_contention.bpf.c:612:28: note: forward declaration of 'struct bpf_iter__kmem_cache'
> > >   612 | int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> > >       |                            ^
> > > 2 errors generated.
> > > make[4]: *** [Makefile.perf:1248: /tmp/tmp.DWo9tIFvWU/util/bpf_skel/.tmp/lock_contention.bpf.o] Error 1
> > > make[4]: *** Waiting for unfinished jobs....
> > > make[3]: *** [Makefile.perf:292: sub-make] Error 2
> > > make[2]: *** [Makefile:76: all] Error 2
> > > make[1]: *** [tests/make:344: make_gen_vmlinux_h_O] Error 1
> > > make: *** [Makefile:109: build-test] Error 2
> > > make: Leaving directory '/home/acme/git/perf-tools-next/tools/perf'
> > >
> > > real        3m43.896s
> > > user        29m30.716s
> > > sys 6m36.609s
> > > ⬢ [acme@toolbox perf-tools-next]$
> > >
> > >
> > >
> > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org>
> > > > ---
> > > >  tools/perf/util/bpf_lock_contention.c         | 50 +++++++++++++++++++
> > > >  .../perf/util/bpf_skel/lock_contention.bpf.c  | 28 +++++++++++
> > > >  tools/perf/util/bpf_skel/lock_data.h          | 12 +++++
> > > >  tools/perf/util/bpf_skel/vmlinux/vmlinux.h    |  8 +++
> > > >  4 files changed, 98 insertions(+)
> > > >
> > > > diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
> > > > index 41a1ad08789511c3..558590c3111390fc 100644
> > > > --- a/tools/perf/util/bpf_lock_contention.c
> > > > +++ b/tools/perf/util/bpf_lock_contention.c
> > > > @@ -12,12 +12,59 @@
> > > >  #include <linux/zalloc.h>
> > > >  #include <linux/string.h>
> > > >  #include <bpf/bpf.h>
> > > > +#include <bpf/btf.h>
> > > >  #include <inttypes.h>
> > > >
> > > >  #include "bpf_skel/lock_contention.skel.h"
> > > >  #include "bpf_skel/lock_data.h"
> > > >
> > > >  static struct lock_contention_bpf *skel;
> > > > +static bool has_slab_iter;
> > > > +
> > > > +static void check_slab_cache_iter(struct lock_contention *con)
> > > > +{
> > > > + struct btf *btf = btf__load_vmlinux_btf();
> > > > + s32 ret;
> > > > +
> > > > + if (btf == NULL) {
> > > > +         pr_debug("BTF loading failed: %s\n", strerror(errno));
> > > > +         return;
> > > > + }
> > > > +
> > > > + ret = btf__find_by_name_kind(btf, "bpf_iter__kmem_cache", BTF_KIND_STRUCT);
> > > > + if (ret < 0) {
> > > > +         bpf_program__set_autoload(skel->progs.slab_cache_iter, false);
> > > > +         pr_debug("slab cache iterator is not available: %d\n", ret);
> > > > +         goto out;
> > > > + }
> > > > +
> > > > + has_slab_iter = true;
> > > > +
> > > > + bpf_map__set_max_entries(skel->maps.slab_caches, con->map_nr_entries);
> > > > +out:
> > > > + btf__free(btf);
> > > > +}
> > > > +
> > > > +static void run_slab_cache_iter(void)
> > > > +{
> > > > + int fd;
> > > > + char buf[256];
> > > > +
> > > > + if (!has_slab_iter)
> > > > +         return;
> > > > +
> > > > + fd = bpf_iter_create(bpf_link__fd(skel->links.slab_cache_iter));
> > > > + if (fd < 0) {
> > > > +         pr_debug("cannot create slab cache iter: %d\n", fd);
> > > > +         return;
> > > > + }
> > > > +
> > > > + /* This will run the bpf program */
> > > > + while (read(fd, buf, sizeof(buf)) > 0)
> > > > +         continue;
> > > > +
> > > > + close(fd);
> > > > +}
> > > >
> > > >  int lock_contention_prepare(struct lock_contention *con)
> > > >  {
> > > > @@ -109,6 +156,8 @@ int lock_contention_prepare(struct lock_contention *con)
> > > >                   skel->rodata->use_cgroup_v2 = 1;
> > > >   }
> > > >
> > > > + check_slab_cache_iter(con);
> > > > +
> > > >   if (lock_contention_bpf__load(skel) < 0) {
> > > >           pr_err("Failed to load lock-contention BPF skeleton\n");
> > > >           return -1;
> > > > @@ -304,6 +353,7 @@ static void account_end_timestamp(struct lock_contention *con)
> > > >
> > > >  int lock_contention_start(void)
> > > >  {
> > > > + run_slab_cache_iter();
> > > >   skel->bss->enabled = 1;
> > > >   return 0;
> > > >  }
> > > > diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > > index 1069bda5d733887f..fd24ccb00faec0ba 100644
> > > > --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > > +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c
> > > > @@ -100,6 +100,13 @@ struct {
> > > >   __uint(max_entries, 1);
> > > >  } cgroup_filter SEC(".maps");
> > > >
> > > > +struct {
> > > > + __uint(type, BPF_MAP_TYPE_HASH);
> > > > + __uint(key_size, sizeof(long));
> > > > + __uint(value_size, sizeof(struct slab_cache_data));
> > > > + __uint(max_entries, 1);
> > > > +} slab_caches SEC(".maps");
> > > > +
> > > >  struct rw_semaphore___old {
> > > >   struct task_struct *owner;
> > > >  } __attribute__((preserve_access_index));
> > > > @@ -136,6 +143,8 @@ int perf_subsys_id = -1;
> > > >
> > > >  __u64 end_ts;
> > > >
> > > > +__u32 slab_cache_id;
> > > > +
> > > >  /* error stat */
> > > >  int task_fail;
> > > >  int stack_fail;
> > > > @@ -563,4 +572,23 @@ int BPF_PROG(end_timestamp)
> > > >   return 0;
> > > >  }
> > > >
> > > > +SEC("iter/kmem_cache")
> > > > +int slab_cache_iter(struct bpf_iter__kmem_cache *ctx)
> > > > +{
> > > > + struct kmem_cache *s = ctx->s;
> > > > + struct slab_cache_data d;
> > > > +
> > > > + if (s == NULL)
> > > > +         return 0;
> > > > +
> > > > + d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT;
> > > > + bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name);
> > > > +
> > > > + if (d.id >= LCB_F_SLAB_ID_END)
> > > > +         return 0;
> > > > +
> > > > + bpf_map_update_elem(&slab_caches, &s, &d, BPF_NOEXIST);
> > > > + return 0;
> > > > +}
> > > > +
> > > >  char LICENSE[] SEC("license") = "Dual BSD/GPL";
> > > > diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h
> > > > index 4f0aae5483745dfa..c15f734d7fc4aecb 100644
> > > > --- a/tools/perf/util/bpf_skel/lock_data.h
> > > > +++ b/tools/perf/util/bpf_skel/lock_data.h
> > > > @@ -32,9 +32,16 @@ struct contention_task_data {
> > > >  #define LCD_F_MMAP_LOCK          (1U << 31)
> > > >  #define LCD_F_SIGHAND_LOCK       (1U << 30)
> > > >
> > > > +#define LCB_F_SLAB_ID_SHIFT      16
> > > > +#define LCB_F_SLAB_ID_START      (1U << 16)
> > > > +#define LCB_F_SLAB_ID_END        (1U << 26)
> > > > +#define LCB_F_SLAB_ID_MASK       0x03FF0000U
> > > > +
> > > >  #define LCB_F_TYPE_MAX           (1U << 7)
> > > >  #define LCB_F_TYPE_MASK          0x0000007FU
> > > >
> > > > +#define SLAB_NAME_MAX  28
> > > > +
> > > >  struct contention_data {
> > > >   u64 total_time;
> > > >   u64 min_time;
> > > > @@ -55,4 +62,9 @@ enum lock_class_sym {
> > > >   LOCK_CLASS_RQLOCK,
> > > >  };
> > > >
> > > > +struct slab_cache_data {
> > > > + u32 id;
> > > > + char name[SLAB_NAME_MAX];
> > > > +};
> > > > +
> > > >  #endif /* UTIL_BPF_SKEL_LOCK_DATA_H */
> > > > diff --git a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > > index 4dcad7b682bdee9c..7b81d3173917fdb5 100644
> > > > --- a/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > > +++ b/tools/perf/util/bpf_skel/vmlinux/vmlinux.h
> > > > @@ -195,4 +195,12 @@ struct bpf_perf_event_data_kern {
> > > >   */
> > > >  struct rq {};
> > > >
> > > > +struct kmem_cache {
> > > > + const char *name;
> > > > +} __attribute__((preserve_access_index));
> > > > +
> > > > +struct bpf_iter__kmem_cache {
> > > > + struct kmem_cache *s;
> > > > +} __attribute__((preserve_access_index));
> > > > +
> > > >  #endif // __VMLINUX_H
> > > > --
> > > > 2.47.0.277.g8800431eea-goog

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
  2024-12-09 20:23       ` Arnaldo Carvalho de Melo
@ 2024-12-09 23:00         ` Andrii Nakryiko
       [not found]           ` <CA+JHD91Ai_ObUye4Unz2e2Hku2BH5_+0q3HyUtf7ay23uDnkjQ@mail.gmail.com>
  0 siblings, 1 reply; 19+ messages in thread
From: Andrii Nakryiko @ 2024-12-09 23:00 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ian Rogers, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Vlastimil Babka,
	Roman Gushchin, Hyeonggon Yoo, Kees Cook

On Mon, Dec 9, 2024 at 12:23 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Mon, Dec 09, 2024 at 01:38:39PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Mon, Dec 09, 2024 at 01:36:52PM -0300, Arnaldo Carvalho de Melo wrote:
> > > On Thu, Nov 07, 2024 at 10:14:57PM -0800, Namhyung Kim wrote:
> > > > Recently the kernel got the kmem_cache iterator to traverse metadata of
> > > > slab objects.  This can be used to symbolize dynamic locks in a slab.
>
> > > > The new slab_caches hash map will have the pointer of the kmem_cache as
> > > > a key and save the name and a id.  The id will be saved in the flags
> > > > part of the lock.
>
> > > Trying to fix this
> >
> > So you have that struct in tools/perf/util/bpf_skel/vmlinux/vmlinux.h,
> > but then, this kernel is old and doesn't have the kmem_cache iterator,
> > so using the generated vmlinux.h will fail the build.
>
> I tried passing the right offset to the iterator so as not to try to use
> a type that isn't in vmlinux.h generated from the old kernel BTF:
>
> +++ b/tools/perf/util/bpf_lock_contention.c
> @@ -52,7 +52,7 @@ static void check_slab_cache_iter(struct lock_contention *con)
>                 pr_debug("slab cache iterator is not available: %d\n", ret);
>                 goto out;
>         } else {
> -               const struct btf_member *s = __btf_type__find_member_by_name(btf, ret, "s");
> +               const struct btf_member *s = __btf_type__find_unnamed_union_with_member_by_name(btf, ret, "s");
>
>                 if (s == NULL) {
>                         skel->rodata->slab_cache_iter_member_offset = -1;
> @@ -60,7 +60,9 @@ static void check_slab_cache_iter(struct lock_contention *con)
>                         goto out;
>                 }
>
>                 skel->rodata->slab_cache_iter_member_offset = s->offset / 8; // bits -> bytes
> +               pr_debug("slab cache iterator kmem_cache pointer offset: %d\n",
> +                        skel->rodata->slab_cache_iter_member_offset);
>         }
>
>
> but the verifier doesn't like that:
>
> ; struct kmem_cache *s = slab_cache_iter_member_offset < 0 ? NULL : @ lock_contention.bpf.c:615
> 12: (7b) *(u64 *)(r10 -8) = r2        ; R2_w=ctx(off=8) R10=fp0 fp-8_w=ctx(off=8)
> ; if (s == NULL) @ lock_contention.bpf.c:619
> 13: (15) if r1 == 0x0 goto pc+22      ; R1=ctx()
> ; d.id = ++slab_cache_id << LCB_F_SLAB_ID_SHIFT; @ lock_contention.bpf.c:622
> 14: (18) r1 = 0xffffc14bcde3a014      ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20)
> 16: (61) r3 = *(u32 *)(r1 +0)         ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20) R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))
> 17: (07) r3 += 1                      ; R3_w=scalar(smin=umin=1,smax=umax=0x100000000,var_off=(0x0; 0x1ffffffff))
> 18: (63) *(u32 *)(r1 +0) = r3         ; R1_w=map_value(map=lock_con.bss,ks=4,vs=40,off=20) R3_w=scalar(smin=umin=1,smax=umax=0x100000000,var_off=(0x0; 0x1ffffffff))
> 19: (67) r3 <<= 16                    ; R3_w=scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000))
> 20: (63) *(u32 *)(r10 -40) = r3       ; R3_w=scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000)) R10=fp0 fp-40=????scalar(smin=umin=0x10000,smax=umax=0x1000000000000,smax32=0x7fff0000,umax32=0xffff0000,var_off=(0x0; 0x1ffffffff0000))
> ; bpf_probe_read_kernel_str(d.name, sizeof(d.name), s->name); @ lock_contention.bpf.c:623
> 21: (79) r3 = *(u64 *)(r2 +96)
> dereference of modified ctx ptr R2 off=8 disallowed
> processed 19 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
> -- END PROG LOAD LOG --
> libbpf: prog 'slab_cache_iter': failed to load: -EACCES
> libbpf: failed to load object 'lock_contention_bpf'
> libbpf: failed to load BPF skeleton 'lock_contention_bpf': -EACCES
> Failed to load lock-contention BPF skeleton
> lock contention BPF setup failed
> root@number:~#
>
> and additionally the type is not like the one you added to the barebones
> vmlinux.h:
>
> ⬢ [acme@toolbox perf-tools-next]$ git show d82e2e170d1c756b | grep 'struct bpf_iter__kmem_cache {' -A3
> +struct bpf_iter__kmem_cache {
> +       struct kmem_cache *s;
> +} __attribute__((preserve_access_index));
> +
> ⬢ [acme@toolbox perf-tools-next]$
>
> But:
>
> ⬢ [acme@toolbox perf-tools-next]$ uname -a
> Linux toolbox 6.13.0-rc2 #1 SMP PREEMPT_DYNAMIC Mon Dec  9 12:33:35 -03 2024 x86_64 GNU/Linux
> ⬢ [acme@toolbox perf-tools-next]$ pahole bpf_iter__kmem_cache
> struct bpf_iter__kmem_cache {
>         union {
>                 struct bpf_iter_meta * meta;             /*     0     8 */
>         };                                               /*     0     8 */
>         union {
>                 struct kmem_cache * s;                   /*     8     8 */
>         };                                               /*     8     8 */
>
>         /* size: 16, cachelines: 1, members: 2 */
>         /* last cacheline: 16 bytes */
> };
>
> ⬢ [acme@toolbox perf-tools-next]$
>
> Do CO-RE handle this?
>

I don't know exactly what the problem you are running into is, but
yes, BPF CO-RE allows handling missing fields, incompatible field type
changes, field renames, etc. All without having to break a
compilation. See [0] (and one subsection after that) for
"documentation" and examples.

  [0] https://nakryiko.com/posts/bpf-core-reference-guide/#defining-own-co-re-relocatable-type-definitions

> - Arnaldo

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

* Re: [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator
       [not found]           ` <CA+JHD91Ai_ObUye4Unz2e2Hku2BH5_+0q3HyUtf7ay23uDnkjQ@mail.gmail.com>
@ 2024-12-10  0:23             ` Andrii Nakryiko
  0 siblings, 0 replies; 19+ messages in thread
From: Andrii Nakryiko @ 2024-12-10  0:23 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Kan Liang,
	Jiri Olsa, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users, Andrii Nakryiko, Song Liu, bpf,
	Stephane Eranian, Vlastimil Babka, Roman Gushchin, Hyeonggon Yoo,
	Kees Cook

On Mon, Dec 9, 2024 at 3:33 PM Arnaldo Carvalho de Melo
<arnaldo.melo@gmail.com> wrote:
>
> On Mon, Dec 9, 2024, 8:00 PM Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote:
>>
>> On Mon, Dec 9, 2024 at 12:23 PM Arnaldo Carvalho de Melo
>> <acme@kernel.org> wrote:
>>
>> > and additionally the type is not like the one you added to the barebones
>> > vmlinux.h:
>>
>> > ⬢ [acme@toolbox perf-tools-next]$ git show d82e2e170d1c756b | grep 'struct bpf_iter__kmem_cache {' -A3
>> > +struct bpf_iter__kmem_cache {
>> > +       struct kmem_cache *s;
>> > +} __attribute__((preserve_access_index));
>> > +
>> > ⬢ [acme@toolbox perf-tools-next]$
>>
>> > But:
>>
>> > ⬢ [acme@toolbox perf-tools-next]$ uname -a
>> > Linux toolbox 6.13.0-rc2 #1 SMP PREEMPT_DYNAMIC Mon Dec  9 12:33:35 -03 2024 x86_64 GNU/Linux
>> > ⬢ [acme@toolbox perf-tools-next]$ pahole bpf_iter__kmem_cache
>> > struct bpf_iter__kmem_cache {
>> >         union {
>> >                 struct bpf_iter_meta * meta;             /*     0     8 */
>> >         };                                               /*     0     8 */
>> >         union {
>> >                 struct kmem_cache * s;                   /*     8     8 */
>> >         };                                               /*     8     8 */
>> >
>> >         /* size: 16, cachelines: 1, members: 2 */
>> >         /* last cacheline: 16 bytes */
>> > };
>>
>> > ⬢ [acme@toolbox perf-tools-next]$
>>
>> > Do CO-RE handle this?
>>
>> I don't know exactly what the problem you are running into is, but
>> yes, BPF CO-RE allows handling missing fields, incompatible field type
>> changes, field renames, etc. All without having to break a
>> compilation. See [0] (and one subsection after that) for
>> "documentation" and examples.
>>
>>   [0] https://nakryiko.com/posts/bpf-core-reference-guide/#defining-own-co-re-relocatable-type-definitions
>
>
>>
>  The doubt is the extra layer of unnamed unions in the BTF for the kernel that's not present in the minimal representation shipped with perf.

anonymous unions or structs are transparent to BPF CO-RE relocation,
so that shouldn't be a problem

>
> - Arnaldo

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

* Re: [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names
  2024-11-18 18:35   ` Namhyung Kim
@ 2024-12-13 17:10     ` Namhyung Kim
  0 siblings, 0 replies; 19+ messages in thread
From: Namhyung Kim @ 2024-12-13 17:10 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Kan Liang, Jiri Olsa, Adrian Hunter,
	Peter Zijlstra, Ingo Molnar, LKML, linux-perf-users,
	Andrii Nakryiko, Song Liu, bpf, Stephane Eranian, Vlastimil Babka,
	Roman Gushchin, Hyeonggon Yoo, Kees Cook

Hello,

On Mon, Nov 18, 2024 at 10:35:43AM -0800, Namhyung Kim wrote:
> On Mon, Nov 11, 2024 at 11:46:37AM -0800, Ian Rogers wrote:
> > On Thu, Nov 7, 2024 at 10:15 PM Namhyung Kim <namhyung@kernel.org> wrote:
> > >
> > > Hello,
> > >
> > > This is to support symbolization of dynamic locks using slab
> > > allocator's metadata.  The kernel support is in the bpf-next tree now.
> > >
> > > It provides the new "kmem_cache" BPF iterator and "bpf_get_kmem_cache"
> > > kfunc to get the information from an address.  The feature detection is
> > > done using BTF type info and it won't have any effect on old kernels.
> > >
> > > v2 changes)
> > >
> > >  * don't use libbpf_get_error()  (Andrii)
> > >
> > > v1) https://lore.kernel.org/linux-perf-users/20241105172635.2463800-1-namhyung@kernel.org
> > >
> > > With this change, it can show locks in a slab object like below.  I
> > > added "&" sign to distinguish them from global locks.
> > 
> > I know the & is intentional but I worry it could later complicate
> > parsing of filters. Perhaps @ is a viable alternative. Other than
> > that:
> > 
> > Acked-by: Ian Rogers <irogers@google.com>
> 
> Thanks for the review!
> 
> I don't think it clashes with BPF sample filters which works on sample
> data generated from a perf_event.  Technically this command doesn't use
> perf_event and just attaches the BPF program to tracepoint directly.
> 
> Also sample filters don't use '&' symbol in the syntax as of now. :)

Can we merge this series if no more feedback?

About the build issue, I think it's transient and it's not the default
to build with generated vmlinux.h.  We could disable the generation but
it might be better to keep it to test other issues.  Anyway, it can be
done independently.

Thanks,
Namhyung


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

end of thread, other threads:[~2024-12-13 17:10 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-08  6:14 [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Namhyung Kim
2024-11-08  6:14 ` [PATCH v2 1/4] perf lock contention: Add and use LCB_F_TYPE_MASK Namhyung Kim
2024-11-08  6:14 ` [PATCH v2 2/4] perf lock contention: Run BPF slab cache iterator Namhyung Kim
2024-12-09 16:36   ` Arnaldo Carvalho de Melo
2024-12-09 16:38     ` Arnaldo Carvalho de Melo
2024-12-09 20:23       ` Arnaldo Carvalho de Melo
2024-12-09 23:00         ` Andrii Nakryiko
     [not found]           ` <CA+JHD91Ai_ObUye4Unz2e2Hku2BH5_+0q3HyUtf7ay23uDnkjQ@mail.gmail.com>
2024-12-10  0:23             ` Andrii Nakryiko
2024-12-09 22:16       ` Namhyung Kim
2024-12-09 22:23         ` Ian Rogers
2024-11-08  6:14 ` [PATCH v2 3/4] perf lock contention: Resolve slab object name using BPF Namhyung Kim
2024-11-12 11:09   ` Vlastimil Babka
2024-11-12 14:50     ` Arnaldo Carvalho de Melo
2024-11-13 14:20       ` Vlastimil Babka
2024-11-18 18:45         ` Namhyung Kim
2024-11-08  6:14 ` [PATCH v2 4/4] perf lock contention: Handle slab objects in -L/--lock-filter option Namhyung Kim
2024-11-11 19:46 ` [PATCH v2 0/4] perf lock contention: Symbolize locks using slab cache names Ian Rogers
2024-11-18 18:35   ` Namhyung Kim
2024-12-13 17:10     ` Namhyung Kim

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).