From: Kunwu Chan <kunwu.chan@gmail.com>
To: sj@kernel.org, akpm@linux-foundation.org
Cc: damon@lists.linux.dev, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, rostedt@goodmis.org,
mhiramat@kernel.org, mathieu.desnoyers@efficios.com,
shuah@kernel.org, lianux.mm@gmail.com,
Kunwu Chan <kunwu.chan@gmail.com>
Subject: [RFC PATCH 7/7] mm/damon/perf: add CONFIG_DAMON_PERF_DEBUG and pipeline health check
Date: Tue, 18 Aug 2026 14:10:31 +0800 [thread overview]
Message-ID: <20260818061031.827057-8-kunwu.chan@linux.dev> (raw)
In-Reply-To: <20260818061031.827057-1-kunwu.chan@linux.dev>
From: Lian Wang <lianux.mm@gmail.com>
Add CONFIG_DAMON_PERF_DEBUG as an optional Kconfig option that
enables pr_debug() output for the observability pipeline via the
damon_perf_dbg() macro. Default off, zero overhead when disabled.
Add a pipeline health check to the observability selftest that
diagnoses which stage is broken when callbacks are zero, using the
existing per-CPU state and counter deltas.
Co-developed-by: Kunwu Chan <kunwu.chan@gmail.com>
Signed-off-by: Kunwu Chan <kunwu.chan@gmail.com>
Signed-off-by: Lian Wang <lianux.mm@gmail.com>
---
mm/damon/Kconfig | 16 ++++++++++++++++
mm/damon/perf/debugfs.c | 5 ++++-
mm/damon/perf/perf.h | 7 +++++++
mm/damon/perf/stats.c | 15 ++++++++++++++-
.../selftests/damon/damon_perf_obs_test.sh | 18 +++++++++++++++++-
5 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
index 9f811510760f..35ec4d12c5b8 100644
--- a/mm/damon/Kconfig
+++ b/mm/damon/Kconfig
@@ -148,4 +148,20 @@ config DAMON_PERF_OBSERVE
static-inline no-ops with zero runtime overhead.
If unsure, say N.
+
+config DAMON_PERF_DEBUG
+ bool "DAMON Perf verbose debugging output"
+ depends on DAMON_PERF_OBSERVE
+ help
+ Enable verbose per-event and per-drain pr_debug() output
+ for the DAMON perf observability pipeline. When enabled,
+ key lifecycle transitions and sampling events are logged
+ at KERN_DEBUG level, visible via dynamic_debug or when
+ DEBUG is defined at compile time.
+
+ This adds dmesg noise and should only be enabled for
+ development or troubleshooting.
+
+ If unsure, say N.
+
endmenu
diff --git a/mm/damon/perf/debugfs.c b/mm/damon/perf/debugfs.c
index c54dd7644ac3..48f3d23c2dbc 100644
--- a/mm/damon/perf/debugfs.c
+++ b/mm/damon/perf/debugfs.c
@@ -132,11 +132,14 @@ int damon_perf_debugfs_init(void)
damon_debugfs_dir = debugfs_create_dir("damon", NULL);
if (damon_debugfs_dir == ERR_PTR(-EEXIST))
damon_debugfs_dir = debugfs_lookup("damon", NULL);
- if (IS_ERR(damon_debugfs_dir))
+ if (IS_ERR(damon_debugfs_dir)) {
+ damon_perf_dbg("debugfs init failed: %ld\n", PTR_ERR(damon_debugfs_dir));
return PTR_ERR(damon_debugfs_dir);
+ }
debugfs_create_file("perf_stats", 0400, damon_debugfs_dir,
NULL, &perf_stats_fops);
+ damon_perf_dbg("debugfs init ok\n");
return 0;
}
diff --git a/mm/damon/perf/perf.h b/mm/damon/perf/perf.h
index 78e23d436336..908c06f2e3db 100644
--- a/mm/damon/perf/perf.h
+++ b/mm/damon/perf/perf.h
@@ -18,6 +18,13 @@
struct perf_event;
#include <linux/types.h>
+#ifdef CONFIG_DAMON_PERF_DEBUG
+#define damon_perf_dbg(fmt, ...) \
+ pr_debug("damon-perf: " fmt, ##__VA_ARGS__)
+#else
+#define damon_perf_dbg(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+#endif
+
struct damon_perf_event;
/*
diff --git a/mm/damon/perf/stats.c b/mm/damon/perf/stats.c
index ae5b0037a31d..e2c1e5764d41 100644
--- a/mm/damon/perf/stats.c
+++ b/mm/damon/perf/stats.c
@@ -67,6 +67,7 @@ void damon_perf_observe_event_created(struct damon_perf_event *event, int cpu)
return;
}
*per_cpu_ptr(event->cpu_state, cpu) = DAMON_PERF_STATE_CREATED;
+ damon_perf_dbg("cpu %d: event created\n", cpu);
damon_perf_cpu_state_advance(cpu, DAMON_PERF_STATE_CREATED);
}
@@ -76,6 +77,7 @@ void damon_perf_observe_event_bound(struct damon_perf_event *event,
if (event->cpu_state)
*per_cpu_ptr(event->cpu_state, cpu) = DAMON_PERF_STATE_BOUND;
damon_perf_cpu_state_advance(cpu, DAMON_PERF_STATE_BOUND);
+ damon_perf_dbg("cpu %d: event bound\n", cpu);
}
void damon_perf_observe_event_enabled(struct damon_perf_event *event,
@@ -84,12 +86,14 @@ void damon_perf_observe_event_enabled(struct damon_perf_event *event,
if (event->cpu_state)
*per_cpu_ptr(event->cpu_state, cpu) = DAMON_PERF_STATE_ENABLED;
damon_perf_cpu_state_advance(cpu, DAMON_PERF_STATE_ENABLED);
+ damon_perf_dbg("cpu %d: event enabled\n", cpu);
}
void damon_perf_observe_event_disabled(struct damon_perf_event *event,
int cpu, int state)
{
/* State unchanged: the event may be re-enabled later. */
+ damon_perf_dbg("cpu %d: event disabled\n", cpu);
}
void damon_perf_observe_event_destroyed(struct damon_perf_event *event, int cpu)
@@ -104,6 +108,7 @@ void damon_perf_observe_event_destroyed(struct damon_perf_event *event, int cpu)
*/
if (event->cpu_state)
*per_cpu_ptr(event->cpu_state, cpu) = DAMON_PERF_STATE_UNINIT;
+ damon_perf_dbg("cpu %d: event destroyed\n", cpu);
}
void damon_perf_observe_event_free(struct damon_perf_event *event)
@@ -111,6 +116,7 @@ void damon_perf_observe_event_free(struct damon_perf_event *event)
if (event->cpu_state) {
free_percpu(event->cpu_state);
event->cpu_state = NULL;
+ damon_perf_dbg("event freed\n");
}
}
@@ -231,6 +237,7 @@ void damon_perf_observe_drain(unsigned int total, unsigned int matched)
{
if (trace_damon_perf_drain_enabled())
trace_damon_perf_drain(total, matched);
+ damon_perf_dbg("drain: total=%u matched=%u\n", total, matched);
}
/*
@@ -291,5 +298,11 @@ void damon_perf_stats_aggregate(struct damon_perf_stats *dst)
int damon_perf_framework_init(void)
{
- return damon_perf_debugfs_init();
+ int ret = damon_perf_debugfs_init();
+
+ if (ret)
+ damon_perf_dbg("framework init failed: %d\n", ret);
+ else
+ damon_perf_dbg("framework init ok\n");
+ return ret;
}
diff --git a/tools/testing/selftests/damon/damon_perf_obs_test.sh b/tools/testing/selftests/damon/damon_perf_obs_test.sh
index 4c4074cdd191..cd567c151ae6 100755
--- a/tools/testing/selftests/damon/damon_perf_obs_test.sh
+++ b/tools/testing/selftests/damon/damon_perf_obs_test.sh
@@ -344,7 +344,7 @@ max_cpu_state() {
} END { print max+0 }' "$1" 2>/dev/null
}
-CPU_ST_BASE=$(max_cpu_state "$STATS_BASE")
+CPU_ST_BASE=$(max_cpu_state /sys/kernel/debug/damon/perf_stats)
if [[ "$CPU_ST_BASE" -ge 1 ]]; then
pass "Event Created (max per-CPU state >= CREATED)"
@@ -431,6 +431,22 @@ VALID=$(delta valid)
ADDR_ZERO=$(delta addr_zero)
KERNEL=$(delta kernel)
ENQUEUE=$(delta enqueue)
+# Pipeline health check: diagnose which stage is broken when
+# callbacks are zero, using the existing per-CPU state and
+# counter deltas. This is a best-effort diagnostic, not a
+# substitute for detailed per-backend debugging.
+if [[ "$CALLBACK" -eq 0 ]]; then
+ CPU_ST_BASE_VAL=$(max_cpu_state /sys/kernel/debug/damon/perf_stats)
+ if [[ "$CPU_ST_BASE_VAL" -le 1 ]]; then
+ echo " Pipeline diagnosis: event not created or bound (state=$CPU_ST_BASE_VAL)"
+ elif [[ "$CPU_ST_BASE_VAL" -eq 2 ]]; then
+ echo " Pipeline diagnosis: event bound but not enabled (state=BOUND)"
+ elif [[ "$ENQUEUE" -eq 0 ]]; then
+ echo " Pipeline diagnosis: PMU not producing data or AUX pipeline broken"
+ else
+ echo " Pipeline diagnosis: samples enqueued but none valid"
+ fi
+fi
DEQUEUE=$(delta dequeue)
OVERFLOW=$(delta overflow)
MATCH=$(delta match)
--
2.43.0
prev parent reply other threads:[~2026-08-18 6:11 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 6:10 [RFC PATCH 0/7] mm/damon/perf: observability framework for hardware-sampled access reports Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 1/7] mm/damon/perf: add observability framework with tracepoints and CONFIG switch Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 2/7] mm/damon/perf: implement observe API and per-CPU statistics engine Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 3/7] mm/damon/perf: add debugfs statistics interface Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 4/7] mm/damon: integrate observe API into vaddr overflow handlers and core drain Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 5/7] selftests/damon: add automated layer-by-layer observability test Kunwu Chan
2026-08-18 6:10 ` [RFC PATCH 6/7] Docs/mm/damon: document the perf observability framework Kunwu Chan
2026-08-18 6:10 ` Kunwu Chan [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260818061031.827057-8-kunwu.chan@linux.dev \
--to=kunwu.chan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=damon@lists.linux.dev \
--cc=lianux.mm@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.org \
--cc=shuah@kernel.org \
--cc=sj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.