[RFC PATCH v3 07/37] mm/damon/core: apply access reports to high level snapshot

SeongJae Park
2025-12-08T06:29:59Z

Now any DAMON API callers can report their observed access information.
The DAMON core layer is just ignoring those, though. Update the core to
use the reported information at building the high level access pattern
snapshot.

Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/linux/damon.h | 1 +
mm/damon/core.c | 68 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/include/linux/damon.h b/include/linux/damon.h
index b8ebb2aa02c8..b04c2e36833a 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -83,6 +83,7 @@ struct damon_region {
unsigned int age;
/* private: Internal value for age calculation. */
unsigned int last_nr_accesses;
+ bool access_reported;
};

/**
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 296117d5e7f7..a14754a47c7f 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -137,6 +137,7 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end)

region->age = 0;
region->last_nr_accesses = 0;
+ region->access_reported = false;

return region;
}
@@ -2745,6 +2746,68 @@ static void kdamond_init_ctx(struct damon_ctx *ctx)
}
}

+static void kdamond_apply_access_report(struct damon_access_report *report,
+ struct damon_target *t, struct damon_ctx *ctx)
+{
+ struct damon_region *r;
+
+ /* todo: make search faster, e.g., binary search? */
+ damon_for_each_region(r, t) {
+ if (report->addr < r->ar.start)
+ continue;
+ if (r->ar.end < report->addr + report->size)
+ continue;
+ if (!r->access_reported)
+ damon_update_region_access_rate(r, true, &ctx->attrs);
+ r->access_reported = true;
+ }
+}
+
+static unsigned int kdamond_apply_zero_access_report(struct damon_ctx *ctx)
+{
+ struct damon_target *t;
+ struct damon_region *r;
+ unsigned int max_nr_accesses = 0;
+
+ damon_for_each_target(t, ctx) {
+ damon_for_each_region(r, t) {
+ if (r->access_reported)
+ r->access_reported = false;
+ else
+ damon_update_region_access_rate(r, false,
+ &ctx->attrs);
+ max_nr_accesses = max(max_nr_accesses, r->nr_accesses);
+ }
+ }
+ return max_nr_accesses;
+}
+
+static unsigned int kdamond_check_reported_accesses(struct damon_ctx *ctx)
+{
+ int i;
+ struct damon_access_report *report;
+ struct damon_target *t;
+
+ /* currently damon_access_report supports only physical address */
+ if (damon_target_has_pid(ctx))
+ return 0;
+
+ mutex_lock(&damon_access_reports_lock);
+ for (i = 0; i < damon_access_reports_len; i++) {
+ report = &damon_access_reports[i];
+ if (time_before(report->report_jiffies,
+ jiffies -
+ usecs_to_jiffies(
+ ctx->attrs.sample_interval)))
+ continue;
+ damon_for_each_target(t, ctx)
+ kdamond_apply_access_report(report, t, ctx);
+ }
+ mutex_unlock(&damon_access_reports_lock);
+ /* For nr_accesses_bp, absence of access should also be reported. */
+ return kdamond_apply_zero_access_report(ctx);
+}
+
/*
* The monitoring daemon that runs as a kernel thread
*/
@@ -2790,7 +2853,10 @@ static int kdamond_fn(void *data)
kdamond_usleep(sample_interval);
ctx->passed_sample_intervals++;

- if (ctx->ops.check_accesses)
+ /* todo: make these non-exclusive */
+ if (ctx->sample_control.primitives_enabled.page_fault)
+ max_nr_accesses = kdamond_check_reported_accesses(ctx);
+ else if (ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);

if (ctx->passed_sample_intervals >= next_aggregation_sis)
--
2.47.3