From: Enze Li <lienze@kylinos.cn>
To: sj@kernel.org, akpm@linux-foundation.org
Cc: damon@lists.linux.dev, linux-mm@kvack.org, enze.li@gmx.com,
Enze Li <lienze@kylinos.cn>
Subject: [PATCH 2/2] mm/damon/modules: introduce prdm module for DAMON
Date: Mon, 15 Dec 2025 22:20:57 +0800 [thread overview]
Message-ID: <20251215142057.588500-3-lienze@kylinos.cn> (raw)
In-Reply-To: <20251215142057.588500-1-lienze@kylinos.cn>
This commit introduces the 'prdm' module, an acronym for Proactive
Reclamation DAMON-based Module. The development of this module was
inspired by the existing DAMON sample code (prcl.c), extending its core
idea into a production-ready, user-friendly module.
The key enhancement over the original sample is the capability to
concurrently monitor and perform proactive reclamation for multiple
user-specified processes. This addresses a significant limitation for
practical deployment, where system-wide memory pressure often originates
from several processes rather than a single one.
While achieving similar proactive reclamation is possible through the
existing damo tool with complex manual configuration, the 'prdm'
module significantly reduces the barrier to entry. Its primary
advantage is simplicity: users only need to provide the PIDs of the
target processes and enable the module. This "set PIDs and turn on"
approach encapsulates the intricate DAMON and DAMOS configurations,
making advanced memory optimization accessible to non-expert users
without requiring deep knowledge of the underlying framework.
The module leverages the DAMON framework to track memory access patterns
and utilizes the DAMOS subsystem to trigger reclamation actions on
identified cold memory regions across all monitored processes.
By building upon the proven concept from the DAMON samples, adding
crucial multi-target support, and prioritizing ease of use, 'prdm'
provides a robust and accessible tool for optimizing memory usage in
real-world scenarios.
Signed-off-by: Enze Li <lienze@kylinos.cn>
---
mm/damon/Kconfig | 2 +
mm/damon/Makefile | 1 +
mm/damon/modules/Kconfig | 19 +++
mm/damon/modules/Makefile | 3 +
mm/damon/modules/prdm.c | 254 ++++++++++++++++++++++++++++++++++++++
5 files changed, 279 insertions(+)
create mode 100644 mm/damon/modules/Kconfig
create mode 100644 mm/damon/modules/Makefile
create mode 100644 mm/damon/modules/prdm.c
diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
index 8c868f7035fc..12e437d3158c 100644
--- a/mm/damon/Kconfig
+++ b/mm/damon/Kconfig
@@ -110,4 +110,6 @@ config DAMON_STAT_ENABLED_DEFAULT
Whether to enable DAMON_STAT by default. Users can disable it in
boot or runtime using its 'enabled' parameter.
+source "mm/damon/modules/Kconfig"
+
endmenu
diff --git a/mm/damon/Makefile b/mm/damon/Makefile
index d8d6bf5f8bff..6bfabf546c26 100644
--- a/mm/damon/Makefile
+++ b/mm/damon/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_DAMON_SYSFS) += sysfs-common.o sysfs-schemes.o sysfs.o
obj-$(CONFIG_DAMON_RECLAIM) += modules-common.o reclaim.o
obj-$(CONFIG_DAMON_LRU_SORT) += modules-common.o lru_sort.o
obj-$(CONFIG_DAMON_STAT) += modules-common.o stat.o
+obj-$(CONFIG_DAMON_PRDM) += modules/
diff --git a/mm/damon/modules/Kconfig b/mm/damon/modules/Kconfig
new file mode 100644
index 000000000000..bce29c0f7224
--- /dev/null
+++ b/mm/damon/modules/Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "DAMON ready-to-use modules"
+
+config DAMON_PRDM
+ tristate "Build proactive reclamation DAMON-based module"
+ depends on DAMON && DAMON_VADDR && m
+ default n
+ help
+ This builds DAMON module for access-aware proactive reclamation of
+ multiple processes.
+
+ The module receives pids, monitor access to the virtual address space
+ of these processes, find memory regions that not accessed, and
+ proactively reclaim the regions.
+
+ If unsure, say N.
+
+endmenu
diff --git a/mm/damon/modules/Makefile b/mm/damon/modules/Makefile
new file mode 100644
index 000000000000..f6ae727410ba
--- /dev/null
+++ b/mm/damon/modules/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DAMON_PRDM) += prdm.o
diff --git a/mm/damon/modules/prdm.c b/mm/damon/modules/prdm.c
new file mode 100644
index 000000000000..c107902f07c7
--- /dev/null
+++ b/mm/damon/modules/prdm.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Proactive Reclamation DAMON-based Module (prdm) is a loadable kernel
+ * module that provides out-of-the-box proactive memory reclamation. It
+ * monitors the access patterns of specified processes, finds regions that seem
+ * infrequently accessed, and proactively pages out those regions.
+ *
+ * Based on samples/damon/prcl.c written by SeongJae Park <sj@kernel.org>.
+ * This module extends the original by adding support for monitoring multiple
+ * target processes concurrently.
+ *
+ * Author: Enze Li <lienze@kylinos.cn>
+ * Copyright (C) 2025 KylinSoft Corporation.
+ */
+
+#define pr_fmt(fmt) "damon-prdm: " fmt
+
+#include <linux/damon.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "damon_prdm."
+
+static struct damon_ctx *ctx;
+static LIST_HEAD(target_list);
+static int target_count;
+
+struct prdm_target {
+ struct pid *ppid;
+ int pid;
+ struct list_head list;
+};
+
+static int damon_prdm_target_pid_store(const char *val,
+ const struct kernel_param *kp);
+static int damon_prdm_target_pid_show(char *buffer,
+ const struct kernel_param *kp);
+
+static const struct kernel_param_ops target_pid_param_ops = {
+ .set = damon_prdm_target_pid_store,
+ .get = damon_prdm_target_pid_show,
+};
+
+static int target_pid __read_mostly;
+module_param_cb(target_pid, &target_pid_param_ops, &target_pid, 0600);
+MODULE_PARM_DESC(target_pid, "Specifies the pids of the target processes to be monitored");
+
+static int damon_prdm_enable_store(const char *val,
+ const struct kernel_param *kp);
+
+static const struct kernel_param_ops enabled_param_ops = {
+ .set = damon_prdm_enable_store,
+ .get = param_get_bool,
+};
+
+static bool enabled __read_mostly;
+module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+MODULE_PARM_DESC(enabled, "Enable or disable DAMON_PRDM");
+
+static int damon_prdm_start(void)
+{
+ struct damon_target *target;
+ struct damos *scheme;
+ struct prdm_target *t;
+ struct list_head *pos;
+ struct task_struct *task;
+ int err, exist_target_num;
+
+ pr_info("start\n");
+
+ if (target_count <= 0)
+ return -EINVAL;
+
+ ctx = damon_new_ctx();
+ if (!ctx)
+ return -ENOMEM;
+ if (damon_select_ops(ctx, DAMON_OPS_VADDR)) {
+ damon_destroy_ctx(ctx);
+ return -EINVAL;
+ }
+
+ exist_target_num = 0;
+ list_for_each(pos, &target_list) {
+ t = list_entry(pos, struct prdm_target, list);
+ task = get_pid_task(t->ppid, PIDTYPE_PID);
+ if (task) {
+ target = damon_new_target();
+ if (!target) {
+ damon_destroy_ctx(ctx);
+ return -ENOMEM;
+ }
+ target->pid = t->ppid;
+ damon_add_target(ctx, target);
+ exist_target_num++;
+ put_task_struct(task);
+ }
+ }
+
+ if (exist_target_num <= 0)
+ return -EINVAL;
+
+ scheme = damon_new_scheme(
+ &(struct damos_access_pattern) {
+ .min_sz_region = PAGE_SIZE,
+ .max_sz_region = ULONG_MAX,
+ .min_nr_accesses = 0,
+ .max_nr_accesses = 0,
+ .min_age_region = 50,
+ .max_age_region = UINT_MAX},
+ DAMOS_PAGEOUT,
+ 0,
+ &(struct damos_quota){},
+ &(struct damos_watermarks){},
+ NUMA_NO_NODE);
+ if (!scheme) {
+ damon_destroy_ctx(ctx);
+ return -ENOMEM;
+ }
+ damon_set_schemes(ctx, &scheme, 1);
+
+ err = damon_start(&ctx, 1, true);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void damon_prdm_stop(void)
+{
+ pr_info("stop\n");
+ if (ctx) {
+ damon_stop(&ctx, 1);
+ damon_destroy_ctx(ctx);
+ ctx = NULL;
+ }
+}
+
+static int damon_prdm_target_pid_store(const char *val,
+ const struct kernel_param *kp)
+{
+ int err;
+ struct prdm_target *pt;
+
+ if (!damon_initialized())
+ return 0;
+
+ err = kstrtoint(val, 0, &target_pid);
+ if (err)
+ return err;
+
+ pt = kmalloc(sizeof(*pt), GFP_KERNEL);
+ if (!pt)
+ return -ENOMEM;
+
+ pt->ppid = find_get_pid(target_pid);
+ pt->pid = target_pid;
+ INIT_LIST_HEAD(&pt->list);
+ list_add_tail(&pt->list, &target_list);
+ target_count++;
+
+ return 0;
+}
+
+static int damon_prdm_target_pid_show(char *buffer,
+ const struct kernel_param *kp)
+{
+ char buf[1024];
+ struct list_head *pos;
+ struct prdm_target *t;
+ struct task_struct *task;
+ int len = 0;
+
+ if (!damon_initialized())
+ return 0;
+
+ len = snprintf(buf, sizeof(buf), "%s:", "Tasks");
+ list_for_each(pos, &target_list) {
+ t = list_entry(pos, struct prdm_target, list);
+ task = get_pid_task(t->ppid, PIDTYPE_PID);
+ if (task) {
+ len += snprintf(buf + len, sizeof(buf) - len, " %d",
+ t->pid);
+ put_task_struct(task);
+ } else {
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " %d(exited)", t->pid);
+ }
+ }
+
+ return scnprintf(buffer, 1024, "%s\n", buf);
+}
+
+static int damon_prdm_enable_store(const char *val,
+ const struct kernel_param *kp)
+{
+ bool is_enabled = enabled;
+ int err;
+
+ if (!damon_initialized())
+ return 0;
+
+ err = kstrtobool(val, &enabled);
+ if (err)
+ return err;
+
+ if (enabled == is_enabled)
+ return 0;
+
+ if (enabled) {
+ err = damon_prdm_start();
+ if (err)
+ enabled = false;
+ return err;
+ }
+ damon_prdm_stop();
+ return 0;
+}
+
+static void __exit damon_prdm_exit(void)
+{
+ struct prdm_target *entry, *tmp;
+
+ pr_debug("%s", __func__);
+ damon_prdm_stop();
+
+ list_for_each_entry_safe(entry, tmp, &target_list, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ INIT_LIST_HEAD(&target_list);
+ target_count = 0;
+}
+
+static int __init damon_prdm_init(void)
+{
+ if (!damon_initialized()) {
+ if (enabled)
+ enabled = false;
+ return -ENOMEM;
+ }
+
+ pr_debug("%s", __func__);
+ return 0;
+}
+
+module_init(damon_prdm_init);
+module_exit(damon_prdm_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("A DAMON module for proactive reclamation of multiple processes");
+MODULE_AUTHOR("SeongJae Park <sj@kernel.org>, Enze Li <lienze@kylinos.cn>");
--
2.43.0
next prev parent reply other threads:[~2025-12-15 14:22 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-15 14:20 [PATCH 0/2] mm/damon: export symbols and introduce prdm module Enze Li
2025-12-15 14:20 ` [PATCH 1/2] mm/damon/core: export necessary symbols Enze Li
2025-12-15 14:20 ` Enze Li [this message]
2025-12-15 23:16 ` [PATCH 0/2] mm/damon: export symbols and introduce prdm module SeongJae Park
2025-12-18 13:46 ` Enze Li
2025-12-19 11:46 ` SeongJae Park
2025-12-21 2:42 ` JaeJoon Jung
2025-12-21 8:12 ` SeongJae Park
2025-12-21 11:04 ` JaeJoon Jung
2025-12-21 19:27 ` SeongJae Park
2025-12-22 20:57 ` JaeJoon Jung
2025-12-22 21:33 ` SeongJae Park
2025-12-22 7:08 ` Enze Li
2025-12-22 15:21 ` SeongJae Park
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=20251215142057.588500-3-lienze@kylinos.cn \
--to=lienze@kylinos.cn \
--cc=akpm@linux-foundation.org \
--cc=damon@lists.linux.dev \
--cc=enze.li@gmx.com \
--cc=linux-mm@kvack.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