linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
@ 2024-11-23  6:09 Shakeel Butt
  2024-11-23  6:46 ` Yosry Ahmed
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Shakeel Butt @ 2024-11-23  6:09 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Muchun Song,
	Vlastimil Babka, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

We are starting to deploy mmap_lock tracepoint monitoring across our
fleet and the early results showed that these tracepoints are consuming
significant amount of CPUs in kernfs_path_from_node when enabled.

It seems like the kernel is trying to resolved the cgroup path in the
fast path of the locking code path when the tracepoints are enabled. In
addition for some application their metrics are regressing when
monitoring is enabled.

The cgroup path resolution can be slow and should not be done in the
fast path. Most userspace tools, like bpftrace, provides functionality
to get the cgroup path from cgroup id, so let's just trace the cgroup
id and the users can use better tools to get the path in the slow path.

Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
---
 include/linux/memcontrol.h       | 18 ++++++++++++
 include/trace/events/mmap_lock.h | 32 ++++++++++----------
 mm/mmap_lock.c                   | 50 ++------------------------------
 3 files changed, 36 insertions(+), 64 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 5502aa8e138e..d82f08cd70cd 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -1046,6 +1046,19 @@ static inline void memcg_memory_event_mm(struct mm_struct *mm,
 
 void split_page_memcg(struct page *head, int old_order, int new_order);
 
+static inline u64 memcg_id_from_mm(struct mm_struct *mm)
+{
+	struct mem_cgroup *memcg;
+	u64 id = 0;
+
+	rcu_read_lock();
+	memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
+	if (likely(memcg))
+		id = cgroup_id(memcg->css.cgroup);
+	rcu_read_unlock();
+	return id;
+}
+
 #else /* CONFIG_MEMCG */
 
 #define MEM_CGROUP_ID_SHIFT	0
@@ -1466,6 +1479,11 @@ void count_memcg_event_mm(struct mm_struct *mm, enum vm_event_item idx)
 static inline void split_page_memcg(struct page *head, int old_order, int new_order)
 {
 }
+
+static inline u64 memcg_id_from_mm(struct mm_struct *mm)
+{
+	return 0;
+}
 #endif /* CONFIG_MEMCG */
 
 /*
diff --git a/include/trace/events/mmap_lock.h b/include/trace/events/mmap_lock.h
index bc2e3ad787b3..5529933d19c5 100644
--- a/include/trace/events/mmap_lock.h
+++ b/include/trace/events/mmap_lock.h
@@ -5,6 +5,7 @@
 #if !defined(_TRACE_MMAP_LOCK_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_MMAP_LOCK_H
 
+#include <linux/memcontrol.h>
 #include <linux/tracepoint.h>
 #include <linux/types.h>
 
@@ -12,64 +13,61 @@ struct mm_struct;
 
 DECLARE_EVENT_CLASS(mmap_lock,
 
-	TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write),
+	TP_PROTO(struct mm_struct *mm, bool write),
 
-	TP_ARGS(mm, memcg_path, write),
+	TP_ARGS(mm, write),
 
 	TP_STRUCT__entry(
 		__field(struct mm_struct *, mm)
-		__string(memcg_path, memcg_path)
+		__field(u64, memcg_id)
 		__field(bool, write)
 	),
 
 	TP_fast_assign(
 		__entry->mm = mm;
-		__assign_str(memcg_path);
+		__entry->memcg_id = memcg_id_from_mm(mm);
 		__entry->write = write;
 	),
 
 	TP_printk(
-		"mm=%p memcg_path=%s write=%s",
-		__entry->mm,
-		__get_str(memcg_path),
+		"mm=%p memcg_id=%llu write=%s",
+		__entry->mm, __entry->memcg_id,
 		__entry->write ? "true" : "false"
 	)
 );
 
 #define DEFINE_MMAP_LOCK_EVENT(name)                                    \
 	DEFINE_EVENT(mmap_lock, name,                                   \
-		TP_PROTO(struct mm_struct *mm, const char *memcg_path,  \
-			bool write),                                    \
-		TP_ARGS(mm, memcg_path, write))
+		TP_PROTO(struct mm_struct *mm, bool write),		\
+		TP_ARGS(mm, write))
 
 DEFINE_MMAP_LOCK_EVENT(mmap_lock_start_locking);
 DEFINE_MMAP_LOCK_EVENT(mmap_lock_released);
 
 TRACE_EVENT(mmap_lock_acquire_returned,
 
-	TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write,
-		bool success),
+	TP_PROTO(struct mm_struct *mm, bool write, bool success),
 
-	TP_ARGS(mm, memcg_path, write, success),
+	TP_ARGS(mm, write, success),
 
 	TP_STRUCT__entry(
 		__field(struct mm_struct *, mm)
-		__string(memcg_path, memcg_path)
+		__field(u64, memcg_id)
 		__field(bool, write)
 		__field(bool, success)
 	),
 
 	TP_fast_assign(
 		__entry->mm = mm;
-		__assign_str(memcg_path);
+		__entry->memcg_id = memcg_id_from_mm(mm);
 		__entry->write = write;
 		__entry->success = success;
 	),
 
 	TP_printk(
-		"mm=%p memcg_path=%s write=%s success=%s",
+		"mm=%p memcg_id=%llu write=%s success=%s",
 		__entry->mm,
-		__get_str(memcg_path),
+		__entry->memcg_id,
 		__entry->write ? "true" : "false",
 		__entry->success ? "true" : "false"
 	)
diff --git a/mm/mmap_lock.c b/mm/mmap_lock.c
index f186d57df2c6..e7dbaf96aa17 100644
--- a/mm/mmap_lock.c
+++ b/mm/mmap_lock.c
@@ -17,51 +17,7 @@ EXPORT_TRACEPOINT_SYMBOL(mmap_lock_start_locking);
 EXPORT_TRACEPOINT_SYMBOL(mmap_lock_acquire_returned);
 EXPORT_TRACEPOINT_SYMBOL(mmap_lock_released);
 
-#ifdef CONFIG_MEMCG
-
-/*
- * Size of the buffer for memcg path names. Ignoring stack trace support,
- * trace_events_hist.c uses MAX_FILTER_STR_VAL for this, so we also use it.
- */
-#define MEMCG_PATH_BUF_SIZE MAX_FILTER_STR_VAL
-
-#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)				\
-	do {								\
-		if (trace_mmap_lock_##type##_enabled()) {		\
-			char buf[MEMCG_PATH_BUF_SIZE];                  \
-			get_mm_memcg_path(mm, buf, sizeof(buf));        \
-			trace_mmap_lock_##type(mm, buf, ##__VA_ARGS__); \
-		}							\
-	} while (0)
-
-#else /* !CONFIG_MEMCG */
-
-#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)                                   \
-	trace_mmap_lock_##type(mm, "", ##__VA_ARGS__)
-
-#endif /* CONFIG_MEMCG */
-
 #ifdef CONFIG_TRACING
-#ifdef CONFIG_MEMCG
-/*
- * Write the given mm_struct's memcg path to a buffer. If the path cannot be
- * determined, empty string is written.
- */
-static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
-{
-	struct mem_cgroup *memcg;
-
-	buf[0] = '\0';
-	memcg = get_mem_cgroup_from_mm(mm);
-	if (memcg == NULL)
-		return;
-	if (memcg->css.cgroup)
-		cgroup_path(memcg->css.cgroup, buf, buflen);
-	css_put(&memcg->css);
-}
-
-#endif /* CONFIG_MEMCG */
-
 /*
  * Trace calls must be in a separate file, as otherwise there's a circular
  * dependency between linux/mmap_lock.h and trace/events/mmap_lock.h.
@@ -69,20 +25,20 @@ static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
 
 void __mmap_lock_do_trace_start_locking(struct mm_struct *mm, bool write)
 {
-	TRACE_MMAP_LOCK_EVENT(start_locking, mm, write);
+	trace_mmap_lock_start_locking(mm, write);
 }
 EXPORT_SYMBOL(__mmap_lock_do_trace_start_locking);
 
 void __mmap_lock_do_trace_acquire_returned(struct mm_struct *mm, bool write,
 					   bool success)
 {
-	TRACE_MMAP_LOCK_EVENT(acquire_returned, mm, write, success);
+	trace_mmap_lock_acquire_returned(mm, write, success);
 }
 EXPORT_SYMBOL(__mmap_lock_do_trace_acquire_returned);
 
 void __mmap_lock_do_trace_released(struct mm_struct *mm, bool write)
 {
-	TRACE_MMAP_LOCK_EVENT(released, mm, write);
+	trace_mmap_lock_released(mm, write);
 }
 EXPORT_SYMBOL(__mmap_lock_do_trace_released);
 #endif /* CONFIG_TRACING */
-- 
2.43.5



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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23  6:09 [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints Shakeel Butt
@ 2024-11-23  6:46 ` Yosry Ahmed
  2024-11-23 21:14   ` Shakeel Butt
  2024-11-23  8:38 ` Vlastimil Babka
  2024-11-23 17:01 ` Matthew Wilcox
  2 siblings, 1 reply; 10+ messages in thread
From: Yosry Ahmed @ 2024-11-23  6:46 UTC (permalink / raw)
  To: Shakeel Butt
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Vlastimil Babka, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Fri, Nov 22, 2024 at 10:10 PM Shakeel Butt <shakeel.butt@linux.dev> wrote:
>
> We are starting to deploy mmap_lock tracepoint monitoring across our
> fleet and the early results showed that these tracepoints are consuming
> significant amount of CPUs in kernfs_path_from_node when enabled.
>
> It seems like the kernel is trying to resolved the cgroup path in the

s/resolved/resolve

> fast path of the locking code path when the tracepoints are enabled. In
> addition for some application their metrics are regressing when
> monitoring is enabled.
>
> The cgroup path resolution can be slow and should not be done in the
> fast path. Most userspace tools, like bpftrace, provides functionality
> to get the cgroup path from cgroup id, so let's just trace the cgroup
> id and the users can use better tools to get the path in the slow path.
>
> Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
> ---
>  include/linux/memcontrol.h       | 18 ++++++++++++
>  include/trace/events/mmap_lock.h | 32 ++++++++++----------
>  mm/mmap_lock.c                   | 50 ++------------------------------
>  3 files changed, 36 insertions(+), 64 deletions(-)
>
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index 5502aa8e138e..d82f08cd70cd 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -1046,6 +1046,19 @@ static inline void memcg_memory_event_mm(struct mm_struct *mm,
>
>  void split_page_memcg(struct page *head, int old_order, int new_order);
>
> +static inline u64 memcg_id_from_mm(struct mm_struct *mm)

The usage of memcg_id here and throughout the patch is a bit confusing
because we have a member called 'id' in struct mem_cgroup, but this
isn't it. This is the cgroup_id of the memcg. I admit it's hard to
distinguish them during naming, but when I first saw the function I
thought it was returning memcg->id.

Maybe just cgroup_id_from_mm()? In cgroup v2, the cgroup id is the
same regardless of the controller anyway, in cgroup v1, it's kinda
natural that we return the cgroup id of the memcg.

I don't feel strongly, but I prefer that we use clearer naming, and
either way a comment may help clarify things.

> +{
> +       struct mem_cgroup *memcg;
> +       u64 id = 0;
> +
> +       rcu_read_lock();
> +       memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
> +       if (likely(memcg))
> +               id = cgroup_id(memcg->css.cgroup);

We return 0 if the memcg is NULL here, shouldn't we return the cgroup
id of the root memcg instead? This is more consistent with
get_mem_cgroup_from_mm(), and makes sure we always return the id of a
valid cgroup.

> +       rcu_read_unlock();
> +       return id;
> +}
> +
>  #else /* CONFIG_MEMCG */
>
>  #define MEM_CGROUP_ID_SHIFT    0
> @@ -1466,6 +1479,11 @@ void count_memcg_event_mm(struct mm_struct *mm, enum vm_event_item idx)
>  static inline void split_page_memcg(struct page *head, int old_order, int new_order)
>  {
>  }
> +
> +static inline u64 memcg_id_from_mm(struct mm_struct *mm)
> +{
> +       return 0;
> +}
>  #endif /* CONFIG_MEMCG */
>
>  /*
> diff --git a/include/trace/events/mmap_lock.h b/include/trace/events/mmap_lock.h
> index bc2e3ad787b3..5529933d19c5 100644
> --- a/include/trace/events/mmap_lock.h
> +++ b/include/trace/events/mmap_lock.h
> @@ -5,6 +5,7 @@
>  #if !defined(_TRACE_MMAP_LOCK_H) || defined(TRACE_HEADER_MULTI_READ)
>  #define _TRACE_MMAP_LOCK_H
>
> +#include <linux/memcontrol.h>
>  #include <linux/tracepoint.h>
>  #include <linux/types.h>
>
> @@ -12,64 +13,61 @@ struct mm_struct;
>
>  DECLARE_EVENT_CLASS(mmap_lock,
>
> -       TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write),
> +       TP_PROTO(struct mm_struct *mm, bool write),
>
> -       TP_ARGS(mm, memcg_path, write),
> +       TP_ARGS(mm, write),
>
>         TP_STRUCT__entry(
>                 __field(struct mm_struct *, mm)
> -               __string(memcg_path, memcg_path)
> +               __field(u64, memcg_id)
>                 __field(bool, write)
>         ),
>
>         TP_fast_assign(
>                 __entry->mm = mm;
> -               __assign_str(memcg_path);
> +               __entry->memcg_id = memcg_id_from_mm(mm);
>                 __entry->write = write;
>         ),
>
>         TP_printk(
> -               "mm=%p memcg_path=%s write=%s",
> -               __entry->mm,
> -               __get_str(memcg_path),
> +               "mm=%p memcg_id=%llu write=%s",
> +               __entry->mm, __entry->memcg_id,
>                 __entry->write ? "true" : "false"
>         )
>  );
>
>  #define DEFINE_MMAP_LOCK_EVENT(name)                                    \
>         DEFINE_EVENT(mmap_lock, name,                                   \
> -               TP_PROTO(struct mm_struct *mm, const char *memcg_path,  \
> -                       bool write),                                    \
> -               TP_ARGS(mm, memcg_path, write))
> +               TP_PROTO(struct mm_struct *mm, bool write),             \
> +               TP_ARGS(mm, write))
>
>  DEFINE_MMAP_LOCK_EVENT(mmap_lock_start_locking);
>  DEFINE_MMAP_LOCK_EVENT(mmap_lock_released);
>
>  TRACE_EVENT(mmap_lock_acquire_returned,
>
> -       TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write,
> -               bool success),
> +       TP_PROTO(struct mm_struct *mm, bool write, bool success),
>
> -       TP_ARGS(mm, memcg_path, write, success),
> +       TP_ARGS(mm, write, success),
>
>         TP_STRUCT__entry(
>                 __field(struct mm_struct *, mm)
> -               __string(memcg_path, memcg_path)
> +               __field(u64, memcg_id)
>                 __field(bool, write)
>                 __field(bool, success)
>         ),
>
>         TP_fast_assign(
>                 __entry->mm = mm;
> -               __assign_str(memcg_path);
> +               __entry->memcg_id = memcg_id_from_mm(mm);
>                 __entry->write = write;
>                 __entry->success = success;
>         ),
>
>         TP_printk(
> -               "mm=%p memcg_path=%s write=%s success=%s",
> +               "mm=%p memcg_id=%llu write=%s success=%s",
>                 __entry->mm,
> -               __get_str(memcg_path),
> +               __entry->memcg_id,
>                 __entry->write ? "true" : "false",
>                 __entry->success ? "true" : "false"
>         )
> diff --git a/mm/mmap_lock.c b/mm/mmap_lock.c
> index f186d57df2c6..e7dbaf96aa17 100644
> --- a/mm/mmap_lock.c
> +++ b/mm/mmap_lock.c
> @@ -17,51 +17,7 @@ EXPORT_TRACEPOINT_SYMBOL(mmap_lock_start_locking);
>  EXPORT_TRACEPOINT_SYMBOL(mmap_lock_acquire_returned);
>  EXPORT_TRACEPOINT_SYMBOL(mmap_lock_released);
>
> -#ifdef CONFIG_MEMCG
> -
> -/*
> - * Size of the buffer for memcg path names. Ignoring stack trace support,
> - * trace_events_hist.c uses MAX_FILTER_STR_VAL for this, so we also use it.
> - */
> -#define MEMCG_PATH_BUF_SIZE MAX_FILTER_STR_VAL
> -
> -#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)                           \
> -       do {                                                            \
> -               if (trace_mmap_lock_##type##_enabled()) {               \
> -                       char buf[MEMCG_PATH_BUF_SIZE];                  \
> -                       get_mm_memcg_path(mm, buf, sizeof(buf));        \
> -                       trace_mmap_lock_##type(mm, buf, ##__VA_ARGS__); \
> -               }                                                       \
> -       } while (0)
> -
> -#else /* !CONFIG_MEMCG */
> -
> -#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)                                   \
> -       trace_mmap_lock_##type(mm, "", ##__VA_ARGS__)
> -
> -#endif /* CONFIG_MEMCG */
> -
>  #ifdef CONFIG_TRACING
> -#ifdef CONFIG_MEMCG
> -/*
> - * Write the given mm_struct's memcg path to a buffer. If the path cannot be
> - * determined, empty string is written.
> - */
> -static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
> -{
> -       struct mem_cgroup *memcg;
> -
> -       buf[0] = '\0';
> -       memcg = get_mem_cgroup_from_mm(mm);
> -       if (memcg == NULL)
> -               return;
> -       if (memcg->css.cgroup)
> -               cgroup_path(memcg->css.cgroup, buf, buflen);
> -       css_put(&memcg->css);
> -}
> -
> -#endif /* CONFIG_MEMCG */
> -
>  /*
>   * Trace calls must be in a separate file, as otherwise there's a circular
>   * dependency between linux/mmap_lock.h and trace/events/mmap_lock.h.
> @@ -69,20 +25,20 @@ static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
>
>  void __mmap_lock_do_trace_start_locking(struct mm_struct *mm, bool write)
>  {
> -       TRACE_MMAP_LOCK_EVENT(start_locking, mm, write);
> +       trace_mmap_lock_start_locking(mm, write);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_start_locking);
>
>  void __mmap_lock_do_trace_acquire_returned(struct mm_struct *mm, bool write,
>                                            bool success)
>  {
> -       TRACE_MMAP_LOCK_EVENT(acquire_returned, mm, write, success);
> +       trace_mmap_lock_acquire_returned(mm, write, success);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_acquire_returned);
>
>  void __mmap_lock_do_trace_released(struct mm_struct *mm, bool write)
>  {
> -       TRACE_MMAP_LOCK_EVENT(released, mm, write);
> +       trace_mmap_lock_released(mm, write);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_released);
>  #endif /* CONFIG_TRACING */
> --
> 2.43.5
>
>


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23  6:09 [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints Shakeel Butt
  2024-11-23  6:46 ` Yosry Ahmed
@ 2024-11-23  8:38 ` Vlastimil Babka
  2024-11-23 21:15   ` Shakeel Butt
  2024-11-23 17:01 ` Matthew Wilcox
  2 siblings, 1 reply; 10+ messages in thread
From: Vlastimil Babka @ 2024-11-23  8:38 UTC (permalink / raw)
  To: Shakeel Butt, Andrew Morton, Sebastian Andrzej Siewior,
	Tejun Heo, Michal Koutny
  Cc: Johannes Weiner, Michal Hocko, Roman Gushchin, Muchun Song,
	Axel Rasmussen, Steven Rostedt, Suren Baghdasaryan, linux-mm,
	cgroups, linux-kernel, Meta kernel team

On 11/23/24 7:09 AM, Shakeel Butt wrote:
> We are starting to deploy mmap_lock tracepoint monitoring across our
> fleet and the early results showed that these tracepoints are consuming
> significant amount of CPUs in kernfs_path_from_node when enabled.
> 
> It seems like the kernel is trying to resolved the cgroup path in the
> fast path of the locking code path when the tracepoints are enabled. In
> addition for some application their metrics are regressing when
> monitoring is enabled.
> 
> The cgroup path resolution can be slow and should not be done in the
> fast path. Most userspace tools, like bpftrace, provides functionality
> to get the cgroup path from cgroup id, so let's just trace the cgroup
> id and the users can use better tools to get the path in the slow path.
> 
> Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>

AFAIU this would also remove the lockdep issue that patch [1] is solving
with RCU conversion. It probably has other benefits on its own too, so
just FYI. It's definitely better to avoid complex operations to gather
tracepoint data, if avoidable.

[1] https://lore.kernel.org/all/20241121175250.EJbI7VMb@linutronix.de/

> ---
>  include/linux/memcontrol.h       | 18 ++++++++++++
>  include/trace/events/mmap_lock.h | 32 ++++++++++----------
>  mm/mmap_lock.c                   | 50 ++------------------------------
>  3 files changed, 36 insertions(+), 64 deletions(-)
> 
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index 5502aa8e138e..d82f08cd70cd 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -1046,6 +1046,19 @@ static inline void memcg_memory_event_mm(struct mm_struct *mm,
>  
>  void split_page_memcg(struct page *head, int old_order, int new_order);
>  
> +static inline u64 memcg_id_from_mm(struct mm_struct *mm)
> +{
> +	struct mem_cgroup *memcg;
> +	u64 id = 0;
> +
> +	rcu_read_lock();
> +	memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
> +	if (likely(memcg))
> +		id = cgroup_id(memcg->css.cgroup);
> +	rcu_read_unlock();
> +	return id;
> +}
> +
>  #else /* CONFIG_MEMCG */
>  
>  #define MEM_CGROUP_ID_SHIFT	0
> @@ -1466,6 +1479,11 @@ void count_memcg_event_mm(struct mm_struct *mm, enum vm_event_item idx)
>  static inline void split_page_memcg(struct page *head, int old_order, int new_order)
>  {
>  }
> +
> +static inline u64 memcg_id_from_mm(struct mm_struct *mm)
> +{
> +	return 0;
> +}
>  #endif /* CONFIG_MEMCG */
>  
>  /*
> diff --git a/include/trace/events/mmap_lock.h b/include/trace/events/mmap_lock.h
> index bc2e3ad787b3..5529933d19c5 100644
> --- a/include/trace/events/mmap_lock.h
> +++ b/include/trace/events/mmap_lock.h
> @@ -5,6 +5,7 @@
>  #if !defined(_TRACE_MMAP_LOCK_H) || defined(TRACE_HEADER_MULTI_READ)
>  #define _TRACE_MMAP_LOCK_H
>  
> +#include <linux/memcontrol.h>
>  #include <linux/tracepoint.h>
>  #include <linux/types.h>
>  
> @@ -12,64 +13,61 @@ struct mm_struct;
>  
>  DECLARE_EVENT_CLASS(mmap_lock,
>  
> -	TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write),
> +	TP_PROTO(struct mm_struct *mm, bool write),
>  
> -	TP_ARGS(mm, memcg_path, write),
> +	TP_ARGS(mm, write),
>  
>  	TP_STRUCT__entry(
>  		__field(struct mm_struct *, mm)
> -		__string(memcg_path, memcg_path)
> +		__field(u64, memcg_id)
>  		__field(bool, write)
>  	),
>  
>  	TP_fast_assign(
>  		__entry->mm = mm;
> -		__assign_str(memcg_path);
> +		__entry->memcg_id = memcg_id_from_mm(mm);
>  		__entry->write = write;
>  	),
>  
>  	TP_printk(
> -		"mm=%p memcg_path=%s write=%s",
> -		__entry->mm,
> -		__get_str(memcg_path),
> +		"mm=%p memcg_id=%llu write=%s",
> +		__entry->mm, __entry->memcg_id,
>  		__entry->write ? "true" : "false"
>  	)
>  );
>  
>  #define DEFINE_MMAP_LOCK_EVENT(name)                                    \
>  	DEFINE_EVENT(mmap_lock, name,                                   \
> -		TP_PROTO(struct mm_struct *mm, const char *memcg_path,  \
> -			bool write),                                    \
> -		TP_ARGS(mm, memcg_path, write))
> +		TP_PROTO(struct mm_struct *mm, bool write),		\
> +		TP_ARGS(mm, write))
>  
>  DEFINE_MMAP_LOCK_EVENT(mmap_lock_start_locking);
>  DEFINE_MMAP_LOCK_EVENT(mmap_lock_released);
>  
>  TRACE_EVENT(mmap_lock_acquire_returned,
>  
> -	TP_PROTO(struct mm_struct *mm, const char *memcg_path, bool write,
> -		bool success),
> +	TP_PROTO(struct mm_struct *mm, bool write, bool success),
>  
> -	TP_ARGS(mm, memcg_path, write, success),
> +	TP_ARGS(mm, write, success),
>  
>  	TP_STRUCT__entry(
>  		__field(struct mm_struct *, mm)
> -		__string(memcg_path, memcg_path)
> +		__field(u64, memcg_id)
>  		__field(bool, write)
>  		__field(bool, success)
>  	),
>  
>  	TP_fast_assign(
>  		__entry->mm = mm;
> -		__assign_str(memcg_path);
> +		__entry->memcg_id = memcg_id_from_mm(mm);
>  		__entry->write = write;
>  		__entry->success = success;
>  	),
>  
>  	TP_printk(
> -		"mm=%p memcg_path=%s write=%s success=%s",
> +		"mm=%p memcg_id=%llu write=%s success=%s",
>  		__entry->mm,
> -		__get_str(memcg_path),
> +		__entry->memcg_id,
>  		__entry->write ? "true" : "false",
>  		__entry->success ? "true" : "false"
>  	)
> diff --git a/mm/mmap_lock.c b/mm/mmap_lock.c
> index f186d57df2c6..e7dbaf96aa17 100644
> --- a/mm/mmap_lock.c
> +++ b/mm/mmap_lock.c
> @@ -17,51 +17,7 @@ EXPORT_TRACEPOINT_SYMBOL(mmap_lock_start_locking);
>  EXPORT_TRACEPOINT_SYMBOL(mmap_lock_acquire_returned);
>  EXPORT_TRACEPOINT_SYMBOL(mmap_lock_released);
>  
> -#ifdef CONFIG_MEMCG
> -
> -/*
> - * Size of the buffer for memcg path names. Ignoring stack trace support,
> - * trace_events_hist.c uses MAX_FILTER_STR_VAL for this, so we also use it.
> - */
> -#define MEMCG_PATH_BUF_SIZE MAX_FILTER_STR_VAL
> -
> -#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)				\
> -	do {								\
> -		if (trace_mmap_lock_##type##_enabled()) {		\
> -			char buf[MEMCG_PATH_BUF_SIZE];                  \
> -			get_mm_memcg_path(mm, buf, sizeof(buf));        \
> -			trace_mmap_lock_##type(mm, buf, ##__VA_ARGS__); \
> -		}							\
> -	} while (0)
> -
> -#else /* !CONFIG_MEMCG */
> -
> -#define TRACE_MMAP_LOCK_EVENT(type, mm, ...)                                   \
> -	trace_mmap_lock_##type(mm, "", ##__VA_ARGS__)
> -
> -#endif /* CONFIG_MEMCG */
> -
>  #ifdef CONFIG_TRACING
> -#ifdef CONFIG_MEMCG
> -/*
> - * Write the given mm_struct's memcg path to a buffer. If the path cannot be
> - * determined, empty string is written.
> - */
> -static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
> -{
> -	struct mem_cgroup *memcg;
> -
> -	buf[0] = '\0';
> -	memcg = get_mem_cgroup_from_mm(mm);
> -	if (memcg == NULL)
> -		return;
> -	if (memcg->css.cgroup)
> -		cgroup_path(memcg->css.cgroup, buf, buflen);
> -	css_put(&memcg->css);
> -}
> -
> -#endif /* CONFIG_MEMCG */
> -
>  /*
>   * Trace calls must be in a separate file, as otherwise there's a circular
>   * dependency between linux/mmap_lock.h and trace/events/mmap_lock.h.
> @@ -69,20 +25,20 @@ static void get_mm_memcg_path(struct mm_struct *mm, char *buf, size_t buflen)
>  
>  void __mmap_lock_do_trace_start_locking(struct mm_struct *mm, bool write)
>  {
> -	TRACE_MMAP_LOCK_EVENT(start_locking, mm, write);
> +	trace_mmap_lock_start_locking(mm, write);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_start_locking);
>  
>  void __mmap_lock_do_trace_acquire_returned(struct mm_struct *mm, bool write,
>  					   bool success)
>  {
> -	TRACE_MMAP_LOCK_EVENT(acquire_returned, mm, write, success);
> +	trace_mmap_lock_acquire_returned(mm, write, success);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_acquire_returned);
>  
>  void __mmap_lock_do_trace_released(struct mm_struct *mm, bool write)
>  {
> -	TRACE_MMAP_LOCK_EVENT(released, mm, write);
> +	trace_mmap_lock_released(mm, write);
>  }
>  EXPORT_SYMBOL(__mmap_lock_do_trace_released);
>  #endif /* CONFIG_TRACING */



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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23  6:09 [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints Shakeel Butt
  2024-11-23  6:46 ` Yosry Ahmed
  2024-11-23  8:38 ` Vlastimil Babka
@ 2024-11-23 17:01 ` Matthew Wilcox
  2024-11-23 21:35   ` Shakeel Butt
  2 siblings, 1 reply; 10+ messages in thread
From: Matthew Wilcox @ 2024-11-23 17:01 UTC (permalink / raw)
  To: Shakeel Butt
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Vlastimil Babka, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Fri, Nov 22, 2024 at 10:09:39PM -0800, Shakeel Butt wrote:
>  	TP_printk(
> -		"mm=%p memcg_path=%s write=%s",
> -		__entry->mm,
> -		__get_str(memcg_path),
> +		"mm=%p memcg_id=%llu write=%s",
> +		__entry->mm, __entry->memcg_id,
>  		__entry->write ? "true" : "false"

Is it actually useful to print out the (hashed) pointer of the mm?
Wouldn't the PID be more useful so you could actually associate it with
a task?



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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23  6:46 ` Yosry Ahmed
@ 2024-11-23 21:14   ` Shakeel Butt
  0 siblings, 0 replies; 10+ messages in thread
From: Shakeel Butt @ 2024-11-23 21:14 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Vlastimil Babka, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Fri, Nov 22, 2024 at 10:46:53PM -0800, Yosry Ahmed wrote:
> On Fri, Nov 22, 2024 at 10:10 PM Shakeel Butt <shakeel.butt@linux.dev> wrote:
> >
> > We are starting to deploy mmap_lock tracepoint monitoring across our
> > fleet and the early results showed that these tracepoints are consuming
> > significant amount of CPUs in kernfs_path_from_node when enabled.
> >
> > It seems like the kernel is trying to resolved the cgroup path in the
> 
> s/resolved/resolve
> 
> > fast path of the locking code path when the tracepoints are enabled. In
> > addition for some application their metrics are regressing when
> > monitoring is enabled.
> >
> > The cgroup path resolution can be slow and should not be done in the
> > fast path. Most userspace tools, like bpftrace, provides functionality
> > to get the cgroup path from cgroup id, so let's just trace the cgroup
> > id and the users can use better tools to get the path in the slow path.
> >
> > Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
> > ---
> >  include/linux/memcontrol.h       | 18 ++++++++++++
> >  include/trace/events/mmap_lock.h | 32 ++++++++++----------
> >  mm/mmap_lock.c                   | 50 ++------------------------------
> >  3 files changed, 36 insertions(+), 64 deletions(-)
> >
> > diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> > index 5502aa8e138e..d82f08cd70cd 100644
> > --- a/include/linux/memcontrol.h
> > +++ b/include/linux/memcontrol.h
> > @@ -1046,6 +1046,19 @@ static inline void memcg_memory_event_mm(struct mm_struct *mm,
> >
> >  void split_page_memcg(struct page *head, int old_order, int new_order);
> >
> > +static inline u64 memcg_id_from_mm(struct mm_struct *mm)
> 
> The usage of memcg_id here and throughout the patch is a bit confusing
> because we have a member called 'id' in struct mem_cgroup, but this
> isn't it. This is the cgroup_id of the memcg. I admit it's hard to
> distinguish them during naming, but when I first saw the function I
> thought it was returning memcg->id.
> 
> Maybe just cgroup_id_from_mm()? In cgroup v2, the cgroup id is the
> same regardless of the controller anyway, in cgroup v1, it's kinda
> natural that we return the cgroup id of the memcg.
> 
> I don't feel strongly, but I prefer that we use clearer naming, and
> either way a comment may help clarify things.
> 

Ack, I will change to cgroup_id_from_mm() but I will keep memcg_id in
the tracepoints.

> > +{
> > +       struct mem_cgroup *memcg;
> > +       u64 id = 0;
> > +
> > +       rcu_read_lock();
> > +       memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
> > +       if (likely(memcg))
> > +               id = cgroup_id(memcg->css.cgroup);
> 
> We return 0 if the memcg is NULL here, shouldn't we return the cgroup
> id of the root memcg instead? This is more consistent with
> get_mem_cgroup_from_mm(), and makes sure we always return the id of a
> valid cgroup.

Good point and I need to add a mem_cgroup_disabled() check as well. Will
do in v2.


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23  8:38 ` Vlastimil Babka
@ 2024-11-23 21:15   ` Shakeel Butt
  0 siblings, 0 replies; 10+ messages in thread
From: Shakeel Butt @ 2024-11-23 21:15 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, Sebastian Andrzej Siewior, Tejun Heo,
	Michal Koutny, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Axel Rasmussen, Steven Rostedt, Suren Baghdasaryan,
	linux-mm, cgroups, linux-kernel, Meta kernel team

On Sat, Nov 23, 2024 at 09:38:09AM +0100, Vlastimil Babka wrote:
> On 11/23/24 7:09 AM, Shakeel Butt wrote:
> > We are starting to deploy mmap_lock tracepoint monitoring across our
> > fleet and the early results showed that these tracepoints are consuming
> > significant amount of CPUs in kernfs_path_from_node when enabled.
> > 
> > It seems like the kernel is trying to resolved the cgroup path in the
> > fast path of the locking code path when the tracepoints are enabled. In
> > addition for some application their metrics are regressing when
> > monitoring is enabled.
> > 
> > The cgroup path resolution can be slow and should not be done in the
> > fast path. Most userspace tools, like bpftrace, provides functionality
> > to get the cgroup path from cgroup id, so let's just trace the cgroup
> > id and the users can use better tools to get the path in the slow path.
> > 
> > Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
> 
> AFAIU this would also remove the lockdep issue that patch [1] is solving
> with RCU conversion. It probably has other benefits on its own too, so
> just FYI. It's definitely better to avoid complex operations to gather
> tracepoint data, if avoidable.
> 
> [1] https://lore.kernel.org/all/20241121175250.EJbI7VMb@linutronix.de/
> 

Thanks for the pointer, I might add a reference to this in the commit
message in next version.


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23 17:01 ` Matthew Wilcox
@ 2024-11-23 21:35   ` Shakeel Butt
  2024-11-23 21:38     ` Vlastimil Babka
  0 siblings, 1 reply; 10+ messages in thread
From: Shakeel Butt @ 2024-11-23 21:35 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Vlastimil Babka, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Sat, Nov 23, 2024 at 05:01:57PM +0000, Matthew Wilcox wrote:
> On Fri, Nov 22, 2024 at 10:09:39PM -0800, Shakeel Butt wrote:
> >  	TP_printk(
> > -		"mm=%p memcg_path=%s write=%s",
> > -		__entry->mm,
> > -		__get_str(memcg_path),
> > +		"mm=%p memcg_id=%llu write=%s",
> > +		__entry->mm, __entry->memcg_id,
> >  		__entry->write ? "true" : "false"
> 
> Is it actually useful to print out the (hashed) pointer of the mm?
> Wouldn't the PID be more useful so you could actually associate it with
> a task?
> 

For our usecase i.e. bpftrace, we don't really care about these prints
as we can directly access the arguments like mm in bpftrace. I wonder if
others are using this hased pointer in some other way. I don't mind
chaning it but I think that would be a separate patch.


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23 21:35   ` Shakeel Butt
@ 2024-11-23 21:38     ` Vlastimil Babka
  2024-11-24  6:26       ` Shakeel Butt
  2024-11-24 13:39       ` Steven Rostedt
  0 siblings, 2 replies; 10+ messages in thread
From: Vlastimil Babka @ 2024-11-23 21:38 UTC (permalink / raw)
  To: Shakeel Butt, Matthew Wilcox
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Roman Gushchin,
	Muchun Song, Axel Rasmussen, Steven Rostedt, Suren Baghdasaryan,
	linux-mm, cgroups, linux-kernel, Meta kernel team

On 11/23/24 22:35, Shakeel Butt wrote:
> On Sat, Nov 23, 2024 at 05:01:57PM +0000, Matthew Wilcox wrote:
>> On Fri, Nov 22, 2024 at 10:09:39PM -0800, Shakeel Butt wrote:
>> >  	TP_printk(
>> > -		"mm=%p memcg_path=%s write=%s",
>> > -		__entry->mm,
>> > -		__get_str(memcg_path),
>> > +		"mm=%p memcg_id=%llu write=%s",
>> > +		__entry->mm, __entry->memcg_id,
>> >  		__entry->write ? "true" : "false"
>> 
>> Is it actually useful to print out the (hashed) pointer of the mm?
>> Wouldn't the PID be more useful so you could actually associate it with
>> a task?
>> 
> 
> For our usecase i.e. bpftrace, we don't really care about these prints
> as we can directly access the arguments like mm in bpftrace. I wonder if
> others are using this hased pointer in some other way. I don't mind
> chaning it but I think that would be a separate patch.

I wonder if it's actually hashed when trace events are obtained in binary
form, i.e. via trace-cmd. Might be hashed only when doing e.g. cat
trace_pipe as that's when the kernel's printk with its hashing is used?

I guess that would be another argument for not using it in the tracepoint,
as it would be a sidechannel...


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23 21:38     ` Vlastimil Babka
@ 2024-11-24  6:26       ` Shakeel Butt
  2024-11-24 13:39       ` Steven Rostedt
  1 sibling, 0 replies; 10+ messages in thread
From: Shakeel Butt @ 2024-11-24  6:26 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Matthew Wilcox, Andrew Morton, Johannes Weiner, Michal Hocko,
	Roman Gushchin, Muchun Song, Axel Rasmussen, Steven Rostedt,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Sat, Nov 23, 2024 at 10:38:59PM +0100, Vlastimil Babka wrote:
> On 11/23/24 22:35, Shakeel Butt wrote:
> > On Sat, Nov 23, 2024 at 05:01:57PM +0000, Matthew Wilcox wrote:
> >> On Fri, Nov 22, 2024 at 10:09:39PM -0800, Shakeel Butt wrote:
> >> >  	TP_printk(
> >> > -		"mm=%p memcg_path=%s write=%s",
> >> > -		__entry->mm,
> >> > -		__get_str(memcg_path),
> >> > +		"mm=%p memcg_id=%llu write=%s",
> >> > +		__entry->mm, __entry->memcg_id,
> >> >  		__entry->write ? "true" : "false"
> >> 
> >> Is it actually useful to print out the (hashed) pointer of the mm?
> >> Wouldn't the PID be more useful so you could actually associate it with
> >> a task?
> >> 
> > 
> > For our usecase i.e. bpftrace, we don't really care about these prints
> > as we can directly access the arguments like mm in bpftrace. I wonder if
> > others are using this hased pointer in some other way. I don't mind
> > chaning it but I think that would be a separate patch.
> 
> I wonder if it's actually hashed when trace events are obtained in binary
> form, i.e. via trace-cmd. Might be hashed only when doing e.g. cat
> trace_pipe as that's when the kernel's printk with its hashing is used?
> 
> I guess that would be another argument for not using it in the tracepoint,
> as it would be a sidechannel...

Yup trace-cmd is showing the unhashed raw pointers for mm. If there is
agreement, I can remove the printk of mm pointer in next version.


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

* Re: [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints
  2024-11-23 21:38     ` Vlastimil Babka
  2024-11-24  6:26       ` Shakeel Butt
@ 2024-11-24 13:39       ` Steven Rostedt
  1 sibling, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2024-11-24 13:39 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Shakeel Butt, Matthew Wilcox, Andrew Morton, Johannes Weiner,
	Michal Hocko, Roman Gushchin, Muchun Song, Axel Rasmussen,
	Suren Baghdasaryan, linux-mm, cgroups, linux-kernel,
	Meta kernel team

On Sat, 23 Nov 2024 22:38:59 +0100
Vlastimil Babka <vbabka@suse.cz> wrote:

> On 11/23/24 22:35, Shakeel Butt wrote:
> > On Sat, Nov 23, 2024 at 05:01:57PM +0000, Matthew Wilcox wrote:  
> >> On Fri, Nov 22, 2024 at 10:09:39PM -0800, Shakeel Butt wrote:  
> >> >  	TP_printk(
> >> > -		"mm=%p memcg_path=%s write=%s",
> >> > -		__entry->mm,
> >> > -		__get_str(memcg_path),
> >> > +		"mm=%p memcg_id=%llu write=%s",
> >> > +		__entry->mm, __entry->memcg_id,
> >> >  		__entry->write ? "true" : "false"  
> >> 
> >> Is it actually useful to print out the (hashed) pointer of the mm?
> >> Wouldn't the PID be more useful so you could actually associate it with
> >> a task?
> >>   
> > 
> > For our usecase i.e. bpftrace, we don't really care about these prints
> > as we can directly access the arguments like mm in bpftrace. I wonder if
> > others are using this hased pointer in some other way. I don't mind
> > chaning it but I think that would be a separate patch.  
> 
> I wonder if it's actually hashed when trace events are obtained in binary
> form, i.e. via trace-cmd. Might be hashed only when doing e.g. cat
> trace_pipe as that's when the kernel's printk with its hashing is used?
> 
> I guess that would be another argument for not using it in the tracepoint,
> as it would be a sidechannel...

This is no more a sidechannel than /proc/kallsyms. It is only accessible
via the privileged users. It's very common and useful to show pointers in
trace events.

You can use eprobes to get information off of pointers too:

 echo 'e:mmap_lock_count mmap_lock/mmap_lock_start_locking count=+0($mm):u32' > /sys/kernel/tracing/dynamic_events

and now you have an event that shows the mm_count of the mm structure.

-- Steve


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

end of thread, other threads:[~2024-11-24 13:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-23  6:09 [PATCH] mm: mmap_lock: optimize mmap_lock tracepoints Shakeel Butt
2024-11-23  6:46 ` Yosry Ahmed
2024-11-23 21:14   ` Shakeel Butt
2024-11-23  8:38 ` Vlastimil Babka
2024-11-23 21:15   ` Shakeel Butt
2024-11-23 17:01 ` Matthew Wilcox
2024-11-23 21:35   ` Shakeel Butt
2024-11-23 21:38     ` Vlastimil Babka
2024-11-24  6:26       ` Shakeel Butt
2024-11-24 13:39       ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox