[PATCH v6 1/6] mm/rmap: add tracepoint for rmap_walk
From: xu.xin16
Date: Thu May 21 2026 - 22:54:56 EST
From: xu xin <xu.xin16@xxxxxxxxxx>
Add trace_rmap_walk_start() and trace_rmap_walk_end() to bracket
reverse mapping walks. Unlike manual clock sampling, these
tracepoints record no timestamp; latency can be computed offline
by tools (e.g., perf, trace-cmd) using the event timestamps.
When tracepoints are disabled, the only cost is a static branch
check (no clock read, no duration calculation), making them
suitable for production use.
The information (folio type, locked state) helps diagnose
performance issues in KSM, anonymous, and file-backed rmap walks.
Signed-off-by: xu xin <xu.xin16@xxxxxxxxxx>
---
include/trace/events/rmap.h | 67 +++++++++++++++++++++++++++++++++++++
mm/rmap.c | 9 +++++
2 files changed, 76 insertions(+)
create mode 100644 include/trace/events/rmap.h
diff --git a/include/trace/events/rmap.h b/include/trace/events/rmap.h
new file mode 100644
index 000000000000..55a319ba6235
--- /dev/null
+++ b/include/trace/events/rmap.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rmap
+
+#if !defined(_TRACE_RMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RMAP_H
+
+#include <linux/tracepoint.h>
+#include <linux/rmap.h>
+
+#define GET_RMAP_PAGE_TYPE(folio) (folio_test_ksm(folio) ? "ksm" : \
+ (folio_test_anon(folio) ? "anon" : "file"))
+
+/**
+ * rmap_walk_template - called for start / stop of rmap_walk.
+ */
+DECLARE_EVENT_CLASS(rmap_walk_template,
+
+ TP_PROTO(struct folio *folio, struct rmap_walk_control *rwc, bool locked),
+
+ TP_ARGS(folio, rwc, locked),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, folio_addr)
+ __field(unsigned long, rwc_addr)
+ __string(page_type, GET_RMAP_PAGE_TYPE(folio))
+ __field(bool, locked)
+ ),
+
+ TP_fast_assign(
+ __entry->folio_addr = (unsigned long)folio;
+ __entry->rwc_addr = (unsigned long)rwc;
+ __assign_str(page_type);
+ __entry->locked = locked;
+ ),
+
+ TP_printk("folio=%p rwc=%p page_type=%s locked=%s",
+ (void *)(unsigned long)__entry->folio_addr,
+ (void *)(unsigned long)__entry->rwc_addr,
+ __get_str(page_type),
+ __entry->locked ? "true" : "false")
+
+);
+
+/**
+ * rmap_walk_start - called before a folio is rmapped.
+ */
+DEFINE_EVENT(rmap_walk_template, rmap_walk_start,
+
+ TP_PROTO(struct folio *folio, struct rmap_walk_control *rwc, bool locked),
+
+ TP_ARGS(folio, rwc, locked)
+);
+
+DEFINE_EVENT(rmap_walk_template, rmap_walk_end,
+
+ TP_PROTO(struct folio *folio, struct rmap_walk_control *rwc, bool locked),
+
+ TP_ARGS(folio, rwc, locked)
+);
+
+
+#endif /* _TRACE_RMAP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+
diff --git a/mm/rmap.c b/mm/rmap.c
index 78b7fb5f367c..52f795f768e1 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -80,6 +80,7 @@
#define CREATE_TRACE_POINTS
#include <trace/events/migrate.h>
+#include <trace/events/rmap.h>
#include "internal.h"
#include "swap.h"
@@ -3098,23 +3099,31 @@ static void rmap_walk_file(struct folio *folio,
void rmap_walk(struct folio *folio, struct rmap_walk_control *rwc)
{
+ trace_rmap_walk_start(folio, rwc, false);
+
if (unlikely(folio_test_ksm(folio)))
rmap_walk_ksm(folio, rwc);
else if (folio_test_anon(folio))
rmap_walk_anon(folio, rwc, false);
else
rmap_walk_file(folio, rwc, false);
+
+ trace_rmap_walk_end(folio, rwc, false);
}
/* Like rmap_walk, but caller holds relevant rmap lock */
void rmap_walk_locked(struct folio *folio, struct rmap_walk_control *rwc)
{
+ trace_rmap_walk_start(folio, rwc, true);
+
/* no ksm support for now */
VM_BUG_ON_FOLIO(folio_test_ksm(folio), folio);
if (folio_test_anon(folio))
rmap_walk_anon(folio, rwc, true);
else
rmap_walk_file(folio, rwc, true);
+
+ trace_rmap_walk_end(folio, rwc, true);
}
#ifdef CONFIG_HUGETLB_PAGE
--
2.25.1