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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox