@@ -386,4 +386,31 @@ void damon_pa_set_primitives(struct damon_ctx *ctx);
#endif /* CONFIG_DAMON_PADDR */
+#ifdef CONFIG_DAMON_PGIDLE
+
+/*
+ * struct damon_pfns_range - Represents a pfn range of [@start, @end).
+ * @start: Start pfn of the range (inclusive).
+ * @end: End pfn of the range (exclusive).
+ *
+ * In case of the page granularity idleness monitoring, an instance of this
+ * struct is pointed by &damon_ctx.arbitrary_target.
+ */
+struct damon_pfns_range {
+ unsigned long start;
+ unsigned long end;
+};
+
+bool damon_pgi_is_idle(unsigned long pfn, unsigned long *pg_size);
+
+/* Monitoring primitives for page granularity idleness monitoring */
+
+void damon_pgi_prepare_access_checks(struct damon_ctx *ctx);
+unsigned int damon_pgi_check_accesses(struct damon_ctx *ctx);
+bool damon_pgi_target_valid(void *t);
+void damon_pgi_set_primitives(struct damon_ctx *ctx);
+
+#endif /* CONFIG_DAMON_PGIDLE */
+
+
#endif /* _DAMON_H */
@@ -37,6 +37,25 @@ TRACE_EVENT(damon_aggregated,
__entry->start, __entry->end, __entry->nr_accesses)
);
+TRACE_EVENT(damon_pgi,
+
+ TP_PROTO(unsigned long pfn, bool accessed),
+
+ TP_ARGS(pfn, accessed),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, pfn)
+ __field(bool, accessed)
+ ),
+
+ TP_fast_assign(
+ __entry->pfn = pfn;
+ __entry->accessed = accessed;
+ ),
+
+ TP_printk("pfn=%lu accessed=%u", __entry->pfn, __entry->accessed)
+);
+
#endif /* _TRACE_DAMON_H */
/* This part must be outside protection */
@@ -42,6 +42,15 @@ config DAMON_PADDR
This builds the default data access monitoring primitives for DAMON
that works for physical address spaces.
+config DAMON_PGIDLE
+ bool "Data access monitoring primitives for page granularity idleness"
+ depends on DAMON && MMU
+ select PAGE_EXTENSION if !64BIT
+ select PAGE_IDLE_FLAG
+ help
+ This builds the default data access monitoring primitives for DAMON
+ that works for page granularity idleness monitoring.
+
config DAMON_VADDR_KUNIT_TEST
bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS
depends on DAMON_VADDR && KUNIT=y
@@ -3,4 +3,5 @@
obj-$(CONFIG_DAMON) := core.o
obj-$(CONFIG_DAMON_VADDR) += prmtv-common.o vaddr.o
obj-$(CONFIG_DAMON_PADDR) += prmtv-common.o paddr.o
+obj-$(CONFIG_DAMON_PGIDLE) += prmtv-common.o pgidle.o
obj-$(CONFIG_DAMON_DBGFS) += dbgfs.o
@@ -7,8 +7,6 @@
#define pr_fmt(fmt) "damon-pa: " fmt
-#include <linux/rmap.h>
-
#include "prmtv-common.h"
/*
new file mode 100644
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DAMON Primitives for Page Granularity Idleness Monitoring
+ *
+ * Author: SeongJae Park <sjpark@amazon.de>
+ */
+
+#define pr_fmt(fmt) "damon-pgi: " fmt
+
+#include <linux/rmap.h>
+
+#include "prmtv-common.h"
+
+#include <trace/events/damon.h>
+
+bool damon_pgi_is_idle(unsigned long pfn, unsigned long *pg_size)
+{
+ return damon_pa_young(PFN_PHYS(pfn), pg_size);
+}
+
+/*
+ * This has no implementations for 'init_target_regions()' and
+ * 'update_target_regions()'. Users should set the initial regions and update
+ * regions by themselves in the 'before_start' and 'after_aggregation'
+ * callbacks, respectively. Or, they can implement and use their own version
+ * of the primitives.
+ */
+
+void damon_pgi_prepare_access_checks(struct damon_ctx *ctx)
+{
+ struct damon_pfns_range *target = ctx->arbitrary_target;
+ unsigned long pfn;
+
+ for (pfn = target->start; pfn < target->end; pfn++)
+ damon_pa_mkold(PFN_PHYS(pfn));
+}
+
+unsigned int damon_pgi_check_accesses(struct damon_ctx *ctx)
+{
+ struct damon_pfns_range *target = ctx->arbitrary_target;
+ unsigned long pfn;
+ unsigned long pg_size = 0;
+
+ for (pfn = target->start; pfn < target->end; pfn++) {
+ pg_size = 0;
+ trace_damon_pgi(pfn, damon_pa_young(PFN_PHYS(pfn), &pg_size));
+ if (pg_size > PAGE_SIZE)
+ pfn += pg_size / PAGE_SIZE - 1;
+ }
+
+ return 0;
+}
+
+bool damon_pgi_target_valid(void *target)
+{
+ return true;
+}
+
+void damon_pgi_set_primitives(struct damon_ctx *ctx)
+{
+ ctx->primitive.init_target_regions = NULL;
+ ctx->primitive.update_target_regions = NULL;
+ ctx->primitive.prepare_access_checks = damon_pgi_prepare_access_checks;
+ ctx->primitive.check_accesses = damon_pgi_check_accesses;
+ ctx->primitive.reset_aggregated = NULL;
+ ctx->primitive.target_valid = damon_pgi_target_valid;
+ ctx->primitive.cleanup = NULL;
+ ctx->primitive.apply_scheme = NULL;
+}