* [RFC PATCH v1 0/4] mm/damon: Support hot application detections
@ 2026-02-02 14:56 gutierrez.asier
2026-02-02 14:56 ` [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules gutierrez.asier
` (5 more replies)
0 siblings, 6 replies; 22+ messages in thread
From: gutierrez.asier @ 2026-02-02 14:56 UTC (permalink / raw)
To: gutierrez.asier, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, sj, damon, akpm, linux-mm, linux-kernel
From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Overview
----------
This patch set introduces a new dynamic mechanism for detecting hot applications
and hot regions in those applications.
Motivation
-----------
Currently DAMON requires the system administrator to provide information about
which application needs to be monitored and all the parameters. Ideally this
should be done automatically, with minimal intervention from the system
administrator.
Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
fragmentation and memory waste. For this reason, most application guides and
system administrators suggest to disable THP.
We would like to detect: 1. which applications are hot in the system and 2.
which memory regions are hot in order to collapse those regions.
Solution
-----------
┌────────────┐ ┌────────────┐
│Damon_module│ │Task_monitor│
└──────┬─────┘ └──────┬─────┘
│ start │
│───────────────────────>│
│ │
│ │────┐
│ │ │ calculate task load
│ │<───┘
│ │
│ │────┐
│ │ │ sort tasks
│ │<───┘
│ │
│ │────┐
│ │ │ start kdamond for top 3 tasks
│ │<───┘
┌──────┴─────┐ ┌──────┴─────┐
│Damon_module│ │Task_monitor│
└────────────┘ └────────────┘
We calculate the task load base on the sum of all the utime for all the threads
in a given task. Once we get total utime, we use the exponential load average
provided by calc_load. The tasks that become cold, the kdamond will be stopped
for them.
In each kdamond, we start with a high min_access value. Our goal is to find the
"maximum" min_access value at which point the DAMON action is applied. In each
cycle, if no action is applied, we lower the min_access.
Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
collapse synchronously and avoid polluting khugepaged and other parts of the MM
subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
which needs the correct vm_flags_t set.
Benchmark
-----------
Asier Gutierrez (4):
mm/damon: Generic context creation for modules
mm/damon: Support for synchrounous huge pages collapse
mm/damon: New module with hot application detection
documentation/mm/damon: Documentation for the dynamic_hugepages
module
.../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++
include/linux/damon.h | 1 +
mm/damon/Kconfig | 7 +
mm/damon/Makefile | 1 +
mm/damon/dynamic_hugepages.c (new) | 579 ++++++++++++++++++
mm/damon/lru_sort.c | 6 +-
mm/damon/modules-common.c | 7 +-
mm/damon/modules-common.h | 5 +-
mm/damon/reclaim.c | 5 +-
mm/damon/vaddr.c | 3 +
10 files changed, 778 insertions(+), 9 deletions(-)
create mode 100644 Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
create mode 100644 mm/damon/dynamic_hugepages.c
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
@ 2026-02-02 14:56 ` gutierrez.asier
2026-02-03 1:16 ` SeongJae Park
2026-02-02 14:56 ` [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse gutierrez.asier
` (4 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: gutierrez.asier @ 2026-02-02 14:56 UTC (permalink / raw)
To: gutierrez.asier, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, sj, damon, akpm, linux-mm, linux-kernel
From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Damon_modules_new_paddr_ctx_target. This works only for physical contexts.
In case of virtual addresses, we should duplicate the code.
It is more elegant to have a generic version of new context creation which
receives the mode as a parameter.
Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
---
mm/damon/lru_sort.c | 6 ++++--
mm/damon/modules-common.c | 7 ++++---
mm/damon/modules-common.h | 5 +++--
mm/damon/reclaim.c | 5 +++--
4 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index 49b4bc294f4e..ac34b02dace8 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -201,7 +201,8 @@ static int damon_lru_sort_apply_parameters(void)
unsigned int hot_thres, cold_thres;
int err;
- err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
+ err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
+ DAMON_OPS_PADDR);
if (err)
return err;
@@ -375,7 +376,8 @@ static int __init damon_lru_sort_init(void)
err = -ENOMEM;
goto out;
}
- err = damon_modules_new_paddr_ctx_target(&ctx, &target);
+ err = damon_modules_new_ctx_target(&ctx, &target,
+ DAMON_OPS_PADDR);
if (err)
goto out;
diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c
index 86d58f8c4f63..5ba24e0ad9a1 100644
--- a/mm/damon/modules-common.c
+++ b/mm/damon/modules-common.c
@@ -14,8 +14,9 @@
* @ctxp: Pointer to save the point to the newly created context
* @targetp: Pointer to save the point to the newly created target
*/
-int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
- struct damon_target **targetp)
+int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
+ struct damon_target **targetp,
+ enum damon_ops_id mode)
{
struct damon_ctx *ctx;
struct damon_target *target;
@@ -24,7 +25,7 @@ int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
if (!ctx)
return -ENOMEM;
- if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
+ if (damon_select_ops(ctx, mode)) {
damon_destroy_ctx(ctx);
return -EINVAL;
}
diff --git a/mm/damon/modules-common.h b/mm/damon/modules-common.h
index f103ad556368..87d8058d7d85 100644
--- a/mm/damon/modules-common.h
+++ b/mm/damon/modules-common.h
@@ -45,5 +45,6 @@
module_param_named(nr_##qt_exceed_name, stat.qt_exceeds, ulong, \
0400);
-int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
- struct damon_target **targetp);
+int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
+ struct damon_target **targetp,
+ enum damon_ops_id mode);
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index 36a582e09eae..b64fb810e096 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -197,7 +197,8 @@ static int damon_reclaim_apply_parameters(void)
struct damos_filter *filter;
int err;
- err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
+ err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
+ DAMON_OPS_PADDR);
if (err)
return err;
@@ -379,7 +380,7 @@ static int __init damon_reclaim_init(void)
err = -ENOMEM;
goto out;
}
- err = damon_modules_new_paddr_ctx_target(&ctx, &target);
+ err = damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_PADDR);
if (err)
goto out;
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
2026-02-02 14:56 ` [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules gutierrez.asier
@ 2026-02-02 14:56 ` gutierrez.asier
2026-02-03 1:23 ` SeongJae Park
2026-02-02 14:56 ` [RFC PATCH v1 3/4] mm/damon: New module with hot application detection gutierrez.asier
` (3 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: gutierrez.asier @ 2026-02-02 14:56 UTC (permalink / raw)
To: gutierrez.asier, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, sj, damon, akpm, linux-mm, linux-kernel
From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
* Support for huge pages collapse, which will be used by
dynamic_hugepages module.
* Include the new module for compilation
Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
---
include/linux/damon.h | 1 +
mm/damon/Kconfig | 7 +++++++
mm/damon/Makefile | 1 +
mm/damon/vaddr.c | 3 +++
4 files changed, 12 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 3813373a9200..de5a994f92c2 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -142,6 +142,7 @@ enum damos_action {
DAMOS_LRU_DEPRIO,
DAMOS_MIGRATE_HOT,
DAMOS_MIGRATE_COLD,
+ DAMOS_COLLAPSE,
DAMOS_STAT, /* Do nothing but only record the stat */
NR_DAMOS_ACTIONS,
};
diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
index 8c868f7035fc..2355aacb6d12 100644
--- a/mm/damon/Kconfig
+++ b/mm/damon/Kconfig
@@ -110,4 +110,11 @@ config DAMON_STAT_ENABLED_DEFAULT
Whether to enable DAMON_STAT by default. Users can disable it in
boot or runtime using its 'enabled' parameter.
+config DAMON_HOT_HUGEPAGE
+ bool "Build DAMON-based collapse of hot regions (DAMON_HOT_HUGEPAGES)"
+ depends on DAMON_VADDR
+ help
+ Collapse hot region into huge pages. Hot regions are determined by
+ DAMON-based sampling
+
endmenu
diff --git a/mm/damon/Makefile b/mm/damon/Makefile
index d8d6bf5f8bff..998bddc17819 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_HOT_HUGEPAGE) += modules-common.o dynamic_hugepages.o
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index 23ed738a0bd6..4acbc1a6a5be 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -970,6 +970,9 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
case DAMOS_NOHUGEPAGE:
madv_action = MADV_NOHUGEPAGE;
break;
+ case DAMOS_COLLAPSE:
+ madv_action = MADV_COLLAPSE;
+ break;
case DAMOS_MIGRATE_HOT:
case DAMOS_MIGRATE_COLD:
return damos_va_migrate(t, r, scheme, sz_filter_passed);
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v1 3/4] mm/damon: New module with hot application detection
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
2026-02-02 14:56 ` [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules gutierrez.asier
2026-02-02 14:56 ` [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse gutierrez.asier
@ 2026-02-02 14:56 ` gutierrez.asier
2026-02-03 5:04 ` SeongJae Park
2026-02-02 14:56 ` [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module gutierrez.asier
` (2 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: gutierrez.asier @ 2026-02-02 14:56 UTC (permalink / raw)
To: gutierrez.asier, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, sj, damon, akpm, linux-mm, linux-kernel
From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
This new module detects hot applications and launches a new kdamond
thread for each of them.
1. It first launches a new kthread called damon_dynamic. This thread
will monitor the tasks in the system by pooling. The tasks are sorted
by utime delta. For the top N tasks, a new kdamond thread will be
launched. Applications which turn cold will have their kdamond
stopped.
2. Initially we don't know the min_access for each of the task. We
want to find the highest min_access when collapses start happening.
For that we have an initial threashold of 90, which we will lower
until a collpase occurs.
Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
---
mm/damon/dynamic_hugepages.c (new) | 579 +++++++++++++++++++++++++++++
1 file changed, 579 insertions(+)
diff --git a/mm/damon/dynamic_hugepages.c b/mm/damon/dynamic_hugepages.c
new file mode 100644
index 000000000000..8b7c1e4d5840
--- /dev/null
+++ b/mm/damon/dynamic_hugepages.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 HUAWEI, Inc.
+ * https://www.huawei.com
+ *
+ * Author: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
+ */
+
+#define pr_fmt(fmt) "damon-dynamic-hotpages: " fmt
+
+#include <linux/damon.h>
+#include <linux/kstrtox.h>
+#include <linux/list_sort.h>
+#include <linux/module.h>
+#include <linux/sched/loadavg.h>
+
+#include "modules-common.h"
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "damon_dynamic_hotpages."
+
+#define MAX_MONITORED_PIDS 3
+#define HIGHEST_MIN_ACCESS 90
+#define HIGH_ACC_THRESHOLD 50
+#define MID_ACC_THRESHOLD 15
+#define LOW_ACC_THRESHOLD 2
+
+static struct task_struct *monitor_thread;
+
+struct mutex enable_disable_lock;
+
+/*
+ * Enable or disable DAMON_HOT_HUGEPAGE.
+ *
+ * You can enable DAMON_HOT_HUGEPAGE by setting the value of this parameter
+ * as ``Y``. Setting it as ``N`` disables DAMON_HOT_HUGEPAGE. Note that
+ * DAMON_HOT_HUGEPAGE could do no real monitoring and reclamation due to the
+ * watermarks-based activation condition. Refer to below descriptions for the
+ * watermarks parameter for this.
+ */
+static bool enabled __read_mostly;
+
+/*
+ * DAMON_HOT_HUGEPAGE monitoring period.
+ */
+static unsigned long monitor_period __read_mostly = 5000000;
+module_param(monitor_period, ulong, 0600);
+
+static long monitored_pids[MAX_MONITORED_PIDS];
+module_param_array(monitored_pids, long, NULL, 0400);
+
+static int damon_dynamic_hotpages_turn(bool on);
+
+static struct damos_quota damon_dynamic_hotpages_quota = {
+ /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */
+ .ms = 10,
+ .sz = 0,
+ .reset_interval = 1000,
+ /* Within the quota, page out older regions first. */
+ .weight_sz = 0,
+ .weight_nr_accesses = 0,
+ .weight_age = 1
+};
+DEFINE_DAMON_MODULES_DAMOS_TIME_QUOTA(damon_dynamic_hotpages_quota);
+
+static struct damos_watermarks damon_dynamic_hotpages_wmarks = {
+ .metric = DAMOS_WMARK_FREE_MEM_RATE,
+ .interval = 5000000, /* 5 seconds */
+ .high = 900, /* 90 percent */
+ .mid = 800, /* 80 percent */
+ .low = 50, /* 5 percent */
+};
+DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_dynamic_hotpages_wmarks);
+
+static struct damon_attrs damon_dynamic_hotpages_mon_attrs = {
+ .sample_interval = 5000, /* 5 ms */
+ .aggr_interval = 100000, /* 100 ms */
+ .ops_update_interval = 0,
+ .min_nr_regions = 10,
+ .max_nr_regions = 1000,
+};
+DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_dynamic_hotpages_mon_attrs);
+
+struct task_monitor_node {
+ pid_t pid;
+
+ struct damon_ctx *ctx;
+ struct damon_target *target;
+ struct damon_call_control call_control;
+ u64 previous_utime;
+ unsigned long load;
+ struct damos_stat stat;
+ int min_access;
+
+ struct list_head list;
+ struct list_head sorted_list;
+ struct list_head active_monitoring;
+};
+
+static void find_top_n(struct list_head *task_monitor,
+ struct list_head *sorted_tasks)
+{
+ struct task_monitor_node *entry, *to_test, *tmp;
+ struct list_head *pos;
+ int i;
+
+ list_for_each_entry(entry, task_monitor, list) {
+ i = 0;
+ list_for_each(pos, sorted_tasks) {
+ i++;
+ to_test = list_entry(pos, struct task_monitor_node, sorted_list);
+
+ if (entry->load > to_test->load) {
+ list_add_tail(&entry->sorted_list, pos);
+
+ i = MAX_MONITORED_PIDS;
+ }
+
+ if (i == MAX_MONITORED_PIDS)
+ break;
+ }
+
+ if (i < MAX_MONITORED_PIDS)
+ list_add_tail(&entry->sorted_list, sorted_tasks);
+ }
+
+ i = 0;
+ list_for_each_entry_safe(entry, tmp, sorted_tasks, sorted_list) {
+ if (i < MAX_MONITORED_PIDS)
+ continue;
+ list_del_init(&entry->sorted_list);
+
+ }
+}
+
+static struct damos *damon_dynamic_hotpages_new_scheme(int min_access,
+ enum damos_action action)
+{
+ struct damos_access_pattern pattern = {
+ /* Find regions having PAGE_SIZE or larger size */
+ .min_sz_region = PMD_SIZE,
+ .max_sz_region = ULONG_MAX,
+ /* and not accessed at all */
+ .min_nr_accesses = min_access,
+ .max_nr_accesses = 100,
+ /* for min_age or more micro-seconds */
+ .min_age_region = 0,
+ .max_age_region = UINT_MAX,
+ };
+
+ return damon_new_scheme(
+ &pattern,
+ /* synchrounous partial collapse as soon as found */
+ action, 0,
+ /* under the quota. */
+ &damon_dynamic_hotpages_quota,
+ /* (De)activate this according to the watermarks. */
+ &damon_dynamic_hotpages_wmarks, NUMA_NO_NODE);
+}
+
+static int damon_dynamic_hotpages_apply_parameters(
+ struct task_monitor_node *monitored_task,
+ int min_access,
+ enum damos_action action)
+{
+ struct damos *scheme;
+ struct damon_ctx *param_ctx;
+ struct damon_target *param_target;
+ struct damos_filter *filter;
+ struct pid *spid;
+ int err;
+
+ err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
+ DAMON_OPS_VADDR);
+ if (err)
+ return err;
+
+ err = -EINVAL;
+ spid = find_get_pid(monitored_task->pid);
+ if (!spid) {
+ put_pid(spid);
+ goto out;
+ }
+
+ param_target->pid = spid;
+
+ err = damon_set_attrs(param_ctx, &damon_dynamic_hotpages_mon_attrs);
+ if (err)
+ goto out;
+
+ err = -ENOMEM;
+ scheme = damon_dynamic_hotpages_new_scheme(min_access, action);
+ if (!scheme)
+ goto out;
+
+ damon_set_schemes(param_ctx, &scheme, 1);
+
+ filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false);
+ if (!filter)
+ goto out;
+ damos_add_filter(scheme, filter);
+
+ err = damon_commit_ctx(monitored_task->ctx, param_ctx);
+out:
+ damon_destroy_ctx(param_ctx);
+ return err;
+}
+
+static int damon_dynamic_hotpages_damon_call_fn(void *arg)
+{
+ struct task_monitor_node *monitored_task = arg;
+ struct damon_ctx *ctx = monitored_task->ctx;
+ struct damos *scheme;
+ int err = 0;
+ int min_access;
+ struct damos_stat stat;
+
+ damon_for_each_scheme(scheme, ctx)
+ stat = scheme->stat;
+ scheme = list_first_entry(&ctx->schemes, struct damos, list);
+
+ if (ctx->passed_sample_intervals < scheme->next_apply_sis)
+ return err;
+
+ if (stat.nr_applied)
+ return err;
+
+ min_access = scheme->pattern.min_nr_accesses;
+
+ if (min_access > HIGH_ACC_THRESHOLD) {
+ min_access = min_access - 10;
+ err = damon_dynamic_hotpages_apply_parameters(
+ monitored_task, min_access, DAMOS_COLLAPSE);
+ } else if (min_access > MID_ACC_THRESHOLD) {
+ min_access = min_access - 5;
+ err = damon_dynamic_hotpages_apply_parameters(
+ monitored_task, min_access, DAMOS_COLLAPSE);
+ } else if (min_access > LOW_ACC_THRESHOLD) {
+ min_access = min_access - 1;
+ err = damon_dynamic_hotpages_apply_parameters(
+ monitored_task, min_access, DAMOS_COLLAPSE);
+ }
+ return err;
+}
+
+static int damon_dynamic_hotpages_init_task(
+ struct task_monitor_node *task_monitor)
+{
+ int err = 0;
+ struct pid *spid;
+ struct damon_ctx *ctx = task_monitor->ctx;
+ struct damon_target *target = task_monitor->target;
+
+ if (!ctx || !target)
+ damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_VADDR);
+
+ if (ctx->kdamond)
+ return 0;
+
+ spid = find_get_pid(task_monitor->pid);
+ if (!spid) {
+ put_pid(spid);
+ return -ESRCH;
+ }
+
+ target->pid = spid;
+
+ if (err)
+ return err;
+
+ task_monitor->call_control.fn = damon_dynamic_hotpages_damon_call_fn;
+ task_monitor->call_control.repeat = true;
+ task_monitor->call_control.data = task_monitor;
+
+ struct damos *scheme =
+ damon_dynamic_hotpages_new_scheme(HIGHEST_MIN_ACCESS, DAMOS_COLLAPSE);
+ if (!scheme)
+ return -ENOMEM;
+
+ damon_set_schemes(ctx, &scheme, 1);
+
+ task_monitor->ctx = ctx;
+ err = damon_start(&task_monitor->ctx, 1, false);
+ if (err)
+ return err;
+
+ return damon_call(task_monitor->ctx, &task_monitor->call_control);
+}
+
+static int add_monitored_task(struct task_struct *task,
+ struct list_head *task_monitor)
+{
+ struct task_struct *thread;
+ struct task_monitor_node *task_node;
+ u64 total_time = 0;
+
+ task_node = kzalloc(sizeof(struct task_monitor_node), GFP_KERNEL);
+ if (!task_node)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&task_node->list);
+ INIT_LIST_HEAD(&task_node->sorted_list);
+ INIT_LIST_HEAD(&task_node->active_monitoring);
+
+ task_node->min_access = HIGHEST_MIN_ACCESS;
+ task_node->pid = task_pid_nr(task);
+
+ list_add_tail(&task_node->list, task_monitor);
+
+ for_each_thread(task, thread)
+ total_time += thread->utime;
+
+ task_node->previous_utime = total_time;
+ return 0;
+}
+
+static int damon_dynamic_hotpages_attach_tasks(
+ struct list_head *task_monitor_sorted,
+ struct list_head *task_monitor_active)
+{
+ struct task_monitor_node *sorted_task_node, *tmp;
+ int err;
+ int i = 0;
+
+ sorted_task_node = list_first_entry(
+ task_monitor_sorted, struct task_monitor_node, sorted_list);
+ while (i < MAX_MONITORED_PIDS && !list_entry_is_head(sorted_task_node,
+ task_monitor_sorted, sorted_list)) {
+ if (sorted_task_node->ctx && sorted_task_node->ctx->kdamond)
+ list_move(&sorted_task_node->active_monitoring,
+ task_monitor_active);
+ else {
+ rcu_read_lock();
+ if (!find_vpid(sorted_task_node->pid)) {
+ sorted_task_node->ctx = NULL;
+ sorted_task_node = list_next_entry(
+ sorted_task_node, sorted_list);
+
+ rcu_read_unlock();
+ continue;
+ }
+ rcu_read_unlock();
+
+ err = damon_dynamic_hotpages_init_task(sorted_task_node);
+ if (err) {
+ sorted_task_node->ctx = NULL;
+ sorted_task_node = list_next_entry(
+ sorted_task_node, sorted_list);
+ continue;
+ }
+
+ list_add(&sorted_task_node->active_monitoring,
+ task_monitor_active);
+ }
+
+ monitored_pids[i] = sorted_task_node->pid;
+ sorted_task_node = list_next_entry(sorted_task_node, sorted_list);
+
+ i++;
+ }
+
+ i = 0;
+ list_for_each_entry_safe(sorted_task_node, tmp, task_monitor_active,
+ active_monitoring) {
+ if (i < MAX_MONITORED_PIDS) {
+ i++;
+ continue;
+ }
+
+ if (sorted_task_node->ctx) {
+ damon_stop(&sorted_task_node->ctx, 1);
+ damon_destroy_ctx(sorted_task_node->ctx);
+ sorted_task_node->ctx = NULL;
+ }
+
+ list_del_init(&sorted_task_node->active_monitoring);
+ }
+ return 0;
+}
+
+static int damon_dynamic_hugepage_sync_monitored_pids(
+ struct list_head *task_monitor,
+ struct list_head *task_monitor_active)
+{
+ u64 total_time, delta;
+ struct task_struct *entry_task, *thread, *current_task;
+ struct task_monitor_node *entry, *next_ptr;
+ struct list_head *pos = task_monitor->next;
+ struct list_head *next_pos;
+ int err = 0;
+
+ LIST_HEAD(task_to_be_removed);
+
+ rcu_read_lock();
+ current_task = next_task(&init_task);
+
+ while ((current_task != &init_task)) {
+ if (pos == task_monitor) {
+ /* We reached the end of monited tasks while still having tasks
+ * in the system. This means that we have new tasks and we should
+ * add the to the monitored tasks
+ */
+ err = add_monitored_task(current_task, task_monitor);
+ if (err)
+ goto out;
+ current_task = next_task(current_task);
+ continue;
+ }
+
+ entry = list_entry(pos, struct task_monitor_node, list);
+ entry_task = find_get_task_by_vpid(entry->pid);
+
+ if (!entry_task) {
+ /* task doesn't exist, remove it */
+ next_pos = pos->next;
+ list_move(&entry->list, &task_to_be_removed);
+ pos = next_pos;
+
+ continue;
+ } else {
+ /* We had this task before, update load times */
+ total_time = 0;
+ for_each_thread(entry_task, thread)
+ total_time += thread->utime;
+
+ delta = total_time - entry->previous_utime;
+ entry->previous_utime = total_time;
+
+ /* Exponential load average to avoid peaks of short time usage,
+ * which may lead to running DAMON for a not really hot task
+ */
+ entry->load = calc_load(entry->load, EXP_15, delta);
+ pos = pos->next;
+ current_task = next_task(current_task);
+ }
+ put_task_struct(entry_task);
+ }
+out:
+ rcu_read_unlock();
+
+ list_for_each_entry_safe(entry, next_ptr, &task_to_be_removed, list) {
+ list_del_init(&entry->list);
+ list_del_init(&entry->sorted_list);
+
+ if (!list_is_head(&entry->active_monitoring,
+ task_monitor_active)) {
+ if (entry->ctx) {
+ damon_stop(&entry->ctx, 1);
+ damon_destroy_ctx(entry->ctx);
+ entry->ctx = NULL;
+ }
+ list_del_init(&entry->active_monitoring);
+ }
+ kfree(entry);
+ }
+
+ return err;
+}
+
+static int damon_manager_monitor_thread(void *data)
+{
+ int err = 0;
+ struct task_monitor_node *entry, *tmp;
+
+ LIST_HEAD(task_monitor);
+ LIST_HEAD(task_monitor_sorted);
+ LIST_HEAD(task_monitor_active);
+
+ while (!kthread_should_stop()) {
+ err = damon_dynamic_hugepage_sync_monitored_pids(&task_monitor,
+ &task_monitor_active);
+ if (err)
+ return err;
+
+ find_top_n(&task_monitor, &task_monitor_sorted);
+
+ err = damon_dynamic_hotpages_attach_tasks(&task_monitor_sorted,
+ &task_monitor_active);
+ if (err)
+ return err;
+
+ schedule_timeout_idle(usecs_to_jiffies(monitor_period));
+
+ list_for_each_entry_safe(entry, tmp, &task_monitor_sorted,
+ sorted_list)
+ list_del_init(&entry->sorted_list);
+ }
+
+ list_for_each_entry_safe(entry, tmp, &task_monitor_active,
+ active_monitoring) {
+ if (entry->ctx) {
+ err = damon_stop(&entry->ctx, 1);
+ damon_destroy_ctx(entry->ctx);
+ entry->ctx = NULL;
+ }
+
+ list_del_init(&entry->active_monitoring);
+ }
+
+ return err;
+}
+
+static int damon_dynamic_hotpages_start_monitor_thread(void)
+{
+ monitor_thread = kthread_create(damon_manager_monitor_thread, NULL,
+ "damon_dynamic");
+
+ if (IS_ERR(monitor_thread))
+ return PTR_ERR(monitor_thread);
+
+ wake_up_process(monitor_thread);
+ return 0;
+}
+
+static int damon_dynamic_hotpages_turn(bool on)
+{
+ int err = 0;
+
+ mutex_lock(&enable_disable_lock);
+ if (!on) {
+ if (monitor_thread) {
+ kthread_stop(monitor_thread);
+ monitor_thread = NULL;
+ }
+ goto out;
+ }
+ err = damon_dynamic_hotpages_start_monitor_thread();
+out:
+ mutex_unlock(&enable_disable_lock);
+ return err;
+}
+
+static int damon_dynamic_hotpages_enabled_store(const char *val,
+ const struct kernel_param *kp)
+{
+ bool is_enabled = enabled;
+ bool enable;
+ int err;
+
+ err = kstrtobool(val, &enable);
+ if (err)
+ return err;
+
+ if (is_enabled == enable)
+ return 0;
+
+ err = damon_dynamic_hotpages_turn(enable);
+ if (err)
+ return err;
+
+ enabled = enable;
+ return err;
+}
+
+static const struct kernel_param_ops enabled_param_ops = {
+ .set = damon_dynamic_hotpages_enabled_store,
+ .get = param_get_bool,
+};
+
+module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+MODULE_PARM_DESC(enabled,
+ "Enable or disable DAMON_DYNAMIC_HUGEPAGES (default: disabled)");
+
+static int __init damon_dynamic_hotpages_init(void)
+{
+ int err;
+
+ /* 'enabled' has set before this function, probably via command line */
+ if (enabled)
+ err = damon_dynamic_hotpages_turn(true);
+
+ if (err && enabled)
+ enabled = false;
+ return err;
+}
+
+module_init(damon_dynamic_hotpages_init);
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
` (2 preceding siblings ...)
2026-02-02 14:56 ` [RFC PATCH v1 3/4] mm/damon: New module with hot application detection gutierrez.asier
@ 2026-02-02 14:56 ` gutierrez.asier
2026-02-03 5:34 ` SeongJae Park
2026-02-03 1:10 ` [RFC PATCH v1 0/4] mm/damon: Support hot application detections SeongJae Park
2026-02-11 6:59 ` SeongJae Park
5 siblings, 1 reply; 22+ messages in thread
From: gutierrez.asier @ 2026-02-02 14:56 UTC (permalink / raw)
To: gutierrez.asier, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, sj, damon, akpm, linux-mm, linux-kernel
From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Documentation for dynamic_hugepage DAMON module.
Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
---
.../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++++++++++++++
1 file changed, 173 insertions(+)
diff --git a/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst b/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
new file mode 100644
index 000000000000..a6afb0910661
--- /dev/null
+++ b/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
@@ -0,0 +1,173 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================
+DAMON-based Dynamic Huge Pages Collapsing
+=========================================
+
+
+DAMON-based dynamic hugepages collapsing (DAMON_HOT_HUGEPAGE) is a kernel module
+that monitors the system and picks the 3 most active tasks. Then, it starts a
+new DAMON thread for each of those 3 tasks, which will collapse hot regions into
+huge pages.
+
+Where Dynamic Huge Pages Collapsing is Required?
+================================================
+
+As main memory availability increases, the number of TLB entries does not
+increase proportionally. This adds more pressure to TLB. Huge pages are a
+solution. However, since turning on transparent huge pages globally may lead to
+fragmentation and memory waste, it is usually turned off.
+
+This module allows to automatically detect hot applications and collapse VMA
+that are hot.
+
+How It Works?
+=============
+
+DAMON_HOT_HUGEPAGE spawns a new kthread which will monitor the applications in
+the system. The monitor thread will calculate the moving average of the sum of
+utimes of all the threads for all the processes. Then, pick the top three and
+launch a damon process to monitor the hot regions in those tasks.
+
+Since we don't know the minaccess number in advance, we set it to 90 initially,
+and we keep decreasing that minaccess until a collapse happens.
+
+If a task turns cold, the monitor thread will detect it (it will not fall in the
+top three hot tasks), and stop the damon thread for that task.
+
+Interface: Module Parameters
+============================
+
+To use this feature, you should first ensure your system is running on a kernel
+that is built with CONFIG_DAMON_HOT_HUGEPAGE=y.
+
+To let sysadmins enable or disable it and tune for the given system,
+DAMON_HOT_HUGEPAGE utilizes module parameters. That is, you can put
+damon_dynamic_hotpages.<parameter>=<value> on the kernel boot command line or
+write proper values to /sys/module/damon_dynamic_hotpages/parameters/<parameter>
+files.
+
+Below are the description of each parameter.
+
+enabled
+-------
+
+Enable or disable DAMON_HOT_HUGEPAGE.
+
+You can enable DAMON_HOT_HUGEPAGE by setting the value of this parameter as Y.
+Setting it as N disables DAMON_HOT_HUGEPAGE. Note that, although
+DAMON_HOT_HUGEPAGE monitors the system and starts damon threads, those threads
+could do no real monitoring due to the watermarks-based activation condition.
+Refer to below descriptions for the watermarks parameter for this.
+
+quota_ms
+--------
+
+Limit of time for collapsing memory regions in milliseconds.
+
+DAMON_HOT_HUGEPAGE tries to use only up to this time within a time window
+(quota_reset_interval_ms) for trying memory collapse. This can be used for
+limiting CPU consumption of DAMONHOT_HUGEPAGE. If the value is zero, the limit
+is disabled.
+
+10 ms by default.
+
+quota_reset_interval_ms
+-----------------------
+
+The time quota charge reset interval in milliseconds.
+
+The charge reset interval for the quota of time (quota_ms). That is,
+DAMON_HOT_HUGEPAGE does not collapse memory for more than quota_ms milliseconds
+or quotasz bytes within quota_reset_interval_ms milliseconds.
+
+1 second by default.
+
+wmarks_interval
+---------------
+
+The watermarks check time interval in microseconds.
+
+Minimal time to wait before checking the watermarks, when DAMON_HOT_HUGEPAGE is
+enabled but inactive due to its watermarks rule. 5 seconds by default.
+
+wmarks_high
+-----------
+
+Free memory rate (per thousand) for the high watermark.
+
+If free memory of the system in bytes per thousand bytes is higher than this,
+DAMON_HOT_HUGEPAGE becomes inactive, so it does nothing but periodically checks
+the watermarks. 200 (20%) by default.
+
+wmarks_mid
+----------
+
+Free memory rate (per thousand) for the middle watermark.
+
+If free memory of the system in bytes per thousand bytes is between this and the
+low watermark, DAMON_HOT_HUGEPAGE becomes active, so starts the monitoring and
+the memory collapsing. 150 (15%) by default.
+
+wmarks_low
+----------
+
+Free memory rate (per thousand) for the low watermark.
+
+If free memory of the system in bytes per thousand bytes is lower than this,
+DAMON_HOT_HUGEPAGE becomes inactive, so it does nothing but periodically checks
+the watermarks. 50 (5%) by default.
+
+sample_interval
+---------------
+
+Sampling interval for the monitoring in microseconds.
+
+The sampling interval of DAMON for the cold memory monitoring. Please refer to
+the DAMON documentation (:doc:usage) for more detail. 5ms by default.
+
+aggr_interval
+-------------
+
+Aggregation interval for the monitoring in microseconds.
+
+The aggregation interval of DAMON for the cold memory monitoring. Please refer
+to the DAMON documentation (:doc:usage) for more detail. 100ms by default.
+
+min_nr_regions
+--------------
+
+Minimum number of monitoring regions.
+
+The minimal number of monitoring regions of DAMON for the cold memory
+monitoring. This can be used to set lower-bound of the monitoring quality. But,
+setting this too high could result in increased monitoring overhead. Please
+refer to the DAMON documentation (:doc:usage) for more detail. 10 by default.
+
+max_nr_regions
+--------------
+
+Maximum number of monitoring regions.
+
+The maximum number of monitoring regions of DAMON for the cold memory
+monitoring. This can be used to set upper-bound of the monitoring overhead.
+However, setting this too low could result in bad monitoring quality. Please
+refer to the DAMON documentation (:doc:usage) for more detail. 1000 by defaults.
+
+monitored_pids The PIDs of the tasks that are being actively monitored by DAMON
+threads
+
+Example
+=======
+Below runtime example commands make DAMON_HOT_HUGEPAGE to find memory regions in
+the 3 most active tasks. It also asks DAMON_HOT_HUGEPAGE to do nothing if the
+system's free memory rate is more than 50%, but start the real works if it
+becomes lower than 40%.
+
+ # cd /sys/module/damon_dynamic_hotpages/parameters/
+ # echo 10 > quota_ms
+ # echo 1000 > quota_reset_interval_ms
+ # echo 500 > wmarks_high
+ # echo 400 > wmarks_mid
+ # echo 200 > wmarks_low
+ # echo Y > enabled
\ No newline at end of file
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
` (3 preceding siblings ...)
2026-02-02 14:56 ` [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module gutierrez.asier
@ 2026-02-03 1:10 ` SeongJae Park
2026-02-03 13:03 ` Gutierrez Asier
2026-02-03 14:25 ` Gutierrez Asier
2026-02-11 6:59 ` SeongJae Park
5 siblings, 2 replies; 22+ messages in thread
From: SeongJae Park @ 2026-02-03 1:10 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
Hello Asier,
Thank you for sharing this nice RFC patch series!
On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> Overview
> ----------
>
> This patch set introduces a new dynamic mechanism for detecting hot applications
> and hot regions in those applications.
>
> Motivation
> -----------
>
> Currently DAMON requires the system administrator to provide information about
> which application needs to be monitored and all the parameters. Ideally this
> should be done automatically, with minimal intervention from the system
> administrator.
>
>
> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
> fragmentation and memory waste. For this reason, most application guides and
> system administrators suggest to disable THP.
>
> We would like to detect: 1. which applications are hot in the system and 2.
> which memory regions are hot in order to collapse those regions.
>
>
> Solution
> -----------
>
> ┌────────────┐ ┌────────────┐
> │Damon_module│ │Task_monitor│
> └──────┬─────┘ └──────┬─────┘
> │ start │
> │───────────────────────>│
> │ │
> │ │────┐
> │ │ │ calculate task load
> │ │<───┘
> │ │
> │ │────┐
> │ │ │ sort tasks
> │ │<───┘
> │ │
> │ │────┐
> │ │ │ start kdamond for top 3 tasks
> │ │<───┘
> ┌──────┴─────┐ ┌──────┴─────┐
> │Damon_module│ │Task_monitor│
> └────────────┘ └────────────┘
>
>
> We calculate the task load base on the sum of all the utime for all the threads
> in a given task. Once we get total utime, we use the exponential load average
> provided by calc_load. The tasks that become cold, the kdamond will be stopped
> for them.
Sounds interesting, and this high level idea makes sense to me. :)
I'd like to further learn a few things. Is there a reason to think the top 3
tasks are enough number of tasks? Also, what if a region was hot and
successfully promoted to use huge pages, but later be cold? Should we also
have a DAMOS scheme for splitting such no-more-hot huge pages?
>
> In each kdamond, we start with a high min_access value. Our goal is to find the
> "maximum" min_access value at which point the DAMON action is applied. In each
> cycle, if no action is applied, we lower the min_access.
Sounds like a nice auto-tuning. And we have DAMOS quota goal for that kind of
auto-tuning. Have you considered using that?
>
> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
> collapse synchronously and avoid polluting khugepaged and other parts of the MM
> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
> which needs the correct vm_flags_t set.
>
> Benchmark
> -----------
Seems you forgot writing this section up. Or, you don't have benchmark results
yet, but only mistakenly wrote the above section header? Either is fine, as
this is just an RFC. Nevertheless, test results and your expected use case of
this patch series will be very helpful.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules
2026-02-02 14:56 ` [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules gutierrez.asier
@ 2026-02-03 1:16 ` SeongJae Park
2026-02-03 13:04 ` Gutierrez Asier
0 siblings, 1 reply; 22+ messages in thread
From: SeongJae Park @ 2026-02-03 1:16 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
Let's use 'mm/damon/modules-common:' as the commit subject prefix.
On Mon, 2 Feb 2026 14:56:46 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> Damon_modules_new_paddr_ctx_target. This works only for physical contexts.
Let's be case-sensitive. s/Damon_/damon_/ ?
> In case of virtual addresses, we should duplicate the code.
>
> It is more elegant to have a generic version of new context creation which
> receives the mode as a parameter.
Makes sense to me.
>
> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
> ---
> mm/damon/lru_sort.c | 6 ++++--
> mm/damon/modules-common.c | 7 ++++---
> mm/damon/modules-common.h | 5 +++--
> mm/damon/reclaim.c | 5 +++--
> 4 files changed, 14 insertions(+), 9 deletions(-)
>
> diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
> index 49b4bc294f4e..ac34b02dace8 100644
> --- a/mm/damon/lru_sort.c
> +++ b/mm/damon/lru_sort.c
> @@ -201,7 +201,8 @@ static int damon_lru_sort_apply_parameters(void)
> unsigned int hot_thres, cold_thres;
> int err;
>
> - err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
> + DAMON_OPS_PADDR);
> if (err)
> return err;
>
> @@ -375,7 +376,8 @@ static int __init damon_lru_sort_init(void)
> err = -ENOMEM;
> goto out;
> }
> - err = damon_modules_new_paddr_ctx_target(&ctx, &target);
> + err = damon_modules_new_ctx_target(&ctx, &target,
> + DAMON_OPS_PADDR);
You could put the above line on the line before that without violating the 80
columns limit :)
> if (err)
> goto out;
>
> diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c
> index 86d58f8c4f63..5ba24e0ad9a1 100644
> --- a/mm/damon/modules-common.c
> +++ b/mm/damon/modules-common.c
> @@ -14,8 +14,9 @@
> * @ctxp: Pointer to save the point to the newly created context
> * @targetp: Pointer to save the point to the newly created target
> */
> -int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
> - struct damon_target **targetp)
> +int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
> + struct damon_target **targetp,
> + enum damon_ops_id mode)
You should also update the kernel-doc comments for the new parameter.
> {
> struct damon_ctx *ctx;
> struct damon_target *target;
> @@ -24,7 +25,7 @@ int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
> if (!ctx)
> return -ENOMEM;
>
> - if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
> + if (damon_select_ops(ctx, mode)) {
> damon_destroy_ctx(ctx);
> return -EINVAL;
> }
> diff --git a/mm/damon/modules-common.h b/mm/damon/modules-common.h
> index f103ad556368..87d8058d7d85 100644
> --- a/mm/damon/modules-common.h
> +++ b/mm/damon/modules-common.h
> @@ -45,5 +45,6 @@
> module_param_named(nr_##qt_exceed_name, stat.qt_exceeds, ulong, \
> 0400);
>
> -int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
> - struct damon_target **targetp);
> +int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
> + struct damon_target **targetp,
> + enum damon_ops_id mode);
> diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
> index 36a582e09eae..b64fb810e096 100644
> --- a/mm/damon/reclaim.c
> +++ b/mm/damon/reclaim.c
> @@ -197,7 +197,8 @@ static int damon_reclaim_apply_parameters(void)
> struct damos_filter *filter;
> int err;
>
> - err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
> + DAMON_OPS_PADDR);
> if (err)
> return err;
>
> @@ -379,7 +380,7 @@ static int __init damon_reclaim_init(void)
> err = -ENOMEM;
> goto out;
> }
> - err = damon_modules_new_paddr_ctx_target(&ctx, &target);
> + err = damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_PADDR);
> if (err)
> goto out;
>
> --
> 2.43.0
Overall, looks good for RFC.
Thanks,
SJ
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse
2026-02-02 14:56 ` [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse gutierrez.asier
@ 2026-02-03 1:23 ` SeongJae Park
2026-02-03 14:04 ` Gutierrez Asier
0 siblings, 1 reply; 22+ messages in thread
From: SeongJae Park @ 2026-02-03 1:23 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Mon, 2 Feb 2026 14:56:47 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> * Support for huge pages collapse, which will be used by
> dynamic_hugepages module.
>
> * Include the new module for compilation
>
> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
> ---
> include/linux/damon.h | 1 +
> mm/damon/Kconfig | 7 +++++++
> mm/damon/Makefile | 1 +
> mm/damon/vaddr.c | 3 +++
> 4 files changed, 12 insertions(+)
>
> diff --git a/include/linux/damon.h b/include/linux/damon.h
> index 3813373a9200..de5a994f92c2 100644
> --- a/include/linux/damon.h
> +++ b/include/linux/damon.h
> @@ -142,6 +142,7 @@ enum damos_action {
> DAMOS_LRU_DEPRIO,
> DAMOS_MIGRATE_HOT,
> DAMOS_MIGRATE_COLD,
> + DAMOS_COLLAPSE,
Please update the kernel-doc comments for this new action, by the time you drop
the RFC tag from this patch series.
> DAMOS_STAT, /* Do nothing but only record the stat */
> NR_DAMOS_ACTIONS,
> };
> diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
> index 8c868f7035fc..2355aacb6d12 100644
> --- a/mm/damon/Kconfig
> +++ b/mm/damon/Kconfig
> @@ -110,4 +110,11 @@ config DAMON_STAT_ENABLED_DEFAULT
> Whether to enable DAMON_STAT by default. Users can disable it in
> boot or runtime using its 'enabled' parameter.
>
> +config DAMON_HOT_HUGEPAGE
> + bool "Build DAMON-based collapse of hot regions (DAMON_HOT_HUGEPAGES)"
> + depends on DAMON_VADDR
> + help
> + Collapse hot region into huge pages. Hot regions are determined by
> + DAMON-based sampling
> +
Apparently you wanted to introduce the above change on the next patch, but
mistakenly added here?
I'm also feeling the name might be better to be simpler. What about... say,
just DAMON_HUGEPAGE? We might want to extend that for general access-aware
huge pages.
> endmenu
> diff --git a/mm/damon/Makefile b/mm/damon/Makefile
> index d8d6bf5f8bff..998bddc17819 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_HOT_HUGEPAGE) += modules-common.o dynamic_hugepages.o
Ditto.
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index 23ed738a0bd6..4acbc1a6a5be 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -970,6 +970,9 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
> case DAMOS_NOHUGEPAGE:
> madv_action = MADV_NOHUGEPAGE;
> break;
> + case DAMOS_COLLAPSE:
> + madv_action = MADV_COLLAPSE;
> + break;
> case DAMOS_MIGRATE_HOT:
> case DAMOS_MIGRATE_COLD:
> return damos_va_migrate(t, r, scheme, sz_filter_passed);
> --
> 2.43.0
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 3/4] mm/damon: New module with hot application detection
2026-02-02 14:56 ` [RFC PATCH v1 3/4] mm/damon: New module with hot application detection gutierrez.asier
@ 2026-02-03 5:04 ` SeongJae Park
2026-02-03 14:21 ` Gutierrez Asier
0 siblings, 1 reply; 22+ messages in thread
From: SeongJae Park @ 2026-02-03 5:04 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Mon, 2 Feb 2026 14:56:48 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> This new module detects hot applications and launches a new kdamond
> thread for each of them.
>
> 1. It first launches a new kthread called damon_dynamic.
I feel like the name is bit ambiguous. What about something more specific to
this module's use case, say, damon_hugepage_monitor or more shortly
damon_hugepaged?
> This thread
> will monitor the tasks in the system by pooling. The tasks are sorted
> by utime delta. For the top N tasks, a new kdamond thread will be
> launched. Applications which turn cold will have their kdamond
> stopped.
>
> 2. Initially we don't know the min_access for each of the task. We
> want to find the highest min_access when collapses start happening.
> For that we have an initial threashold of 90, which we will lower
> until a collpase occurs.
As I asked to the cover letter, I'm curious if you considered using DAMOS quota
goal. Let's continue the discussion on the cover letter, though.
>
> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
> ---
> mm/damon/dynamic_hugepages.c (new) | 579 +++++++++++++++++++++++++++++
> 1 file changed, 579 insertions(+)
>
> diff --git a/mm/damon/dynamic_hugepages.c b/mm/damon/dynamic_hugepages.c
I think the file name could be simpler, say, hugepage.c ?
> new file mode 100644
> index 000000000000..8b7c1e4d5840
> --- /dev/null
> +++ b/mm/damon/dynamic_hugepages.c
> @@ -0,0 +1,579 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 HUAWEI, Inc.
Captain, it's 2026! :)
> + * https://www.huawei.com
> + *
> + * Author: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> + */
> +
> +#define pr_fmt(fmt) "damon-dynamic-hotpages: " fmt
Again, I'd prefer simpler one, like, "damon-hugepage: "
> +
> +#include <linux/damon.h>
> +#include <linux/kstrtox.h>
> +#include <linux/list_sort.h>
> +#include <linux/module.h>
> +#include <linux/sched/loadavg.h>
> +
> +#include "modules-common.h"
> +
> +#ifdef MODULE_PARAM_PREFIX
> +#undef MODULE_PARAM_PREFIX
> +#endif
> +#define MODULE_PARAM_PREFIX "damon_dynamic_hotpages."
Ditto. Maybe "damon_hugepage."
> +
> +#define MAX_MONITORED_PIDS 3
> +#define HIGHEST_MIN_ACCESS 90
> +#define HIGH_ACC_THRESHOLD 50
> +#define MID_ACC_THRESHOLD 15
> +#define LOW_ACC_THRESHOLD 2
> +
> +static struct task_struct *monitor_thread;
> +
> +struct mutex enable_disable_lock;
> +
> +/*
> + * Enable or disable DAMON_HOT_HUGEPAGE.
> + *
> + * You can enable DAMON_HOT_HUGEPAGE by setting the value of this parameter
> + * as ``Y``. Setting it as ``N`` disables DAMON_HOT_HUGEPAGE. Note that
> + * DAMON_HOT_HUGEPAGE could do no real monitoring and reclamation due to the
> + * watermarks-based activation condition. Refer to below descriptions for the
> + * watermarks parameter for this.
Do you willing to use watermarks? Can you further explain how you will use it
in your use case?
> + */
> +static bool enabled __read_mostly;
> +
> +/*
> + * DAMON_HOT_HUGEPAGE monitoring period.
> + */
> +static unsigned long monitor_period __read_mostly = 5000000;
> +module_param(monitor_period, ulong, 0600);
What is the time unit of this parameter? Documenting it would be nice.
> +
> +static long monitored_pids[MAX_MONITORED_PIDS];
> +module_param_array(monitored_pids, long, NULL, 0400);
> +
> +static int damon_dynamic_hotpages_turn(bool on);
Seems the above declaration is not really needed?
> +
> +static struct damos_quota damon_dynamic_hotpages_quota = {
> + /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */
> + .ms = 10,
> + .sz = 0,
> + .reset_interval = 1000,
> + /* Within the quota, page out older regions first. */
You don't page out, but collapse, right? The coment may need to be updated.
> + .weight_sz = 0,
> + .weight_nr_accesses = 0,
> + .weight_age = 1
> +};
> +DEFINE_DAMON_MODULES_DAMOS_TIME_QUOTA(damon_dynamic_hotpages_quota);
> +
> +static struct damos_watermarks damon_dynamic_hotpages_wmarks = {
> + .metric = DAMOS_WMARK_FREE_MEM_RATE,
> + .interval = 5000000, /* 5 seconds */
> + .high = 900, /* 90 percent */
> + .mid = 800, /* 80 percent */
> + .low = 50, /* 5 percent */
> +};
> +DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_dynamic_hotpages_wmarks);
What's the point of setting watermarks here, in hugepage use case?
> +
> +static struct damon_attrs damon_dynamic_hotpages_mon_attrs = {
> + .sample_interval = 5000, /* 5 ms */
> + .aggr_interval = 100000, /* 100 ms */
This means nr_accesses of each region can be only up to 20 (100ms / 5ms).
IIUC, you are auto-tuning the DAMOS target access pattern's min_nr_accesses
starting from 90. If I'm not wrong, you may better to start from 20.
> + .ops_update_interval = 0,
> + .min_nr_regions = 10,
> + .max_nr_regions = 1000,
> +};
> +DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_dynamic_hotpages_mon_attrs);
> +
> +struct task_monitor_node {
> + pid_t pid;
> +
> + struct damon_ctx *ctx;
> + struct damon_target *target;
> + struct damon_call_control call_control;
> + u64 previous_utime;
> + unsigned long load;
> + struct damos_stat stat;
> + int min_access;
> +
> + struct list_head list;
> + struct list_head sorted_list;
> + struct list_head active_monitoring;
> +};
> +
> +static void find_top_n(struct list_head *task_monitor,
> + struct list_head *sorted_tasks)
You ain't need to put that much tabs on the above line.
> +{
> + struct task_monitor_node *entry, *to_test, *tmp;
> + struct list_head *pos;
> + int i;
> +
> + list_for_each_entry(entry, task_monitor, list) {
> + i = 0;
> + list_for_each(pos, sorted_tasks) {
> + i++;
> + to_test = list_entry(pos, struct task_monitor_node, sorted_list);
I'd recommend to use list_for_each_entry() here, if possible.
> +
> + if (entry->load > to_test->load) {
> + list_add_tail(&entry->sorted_list, pos);
> +
The above new line seems unnecessary.
> + i = MAX_MONITORED_PIDS;
> + }
> +
> + if (i == MAX_MONITORED_PIDS)
> + break;
> + }
> +
> + if (i < MAX_MONITORED_PIDS)
> + list_add_tail(&entry->sorted_list, sorted_tasks);
> + }
> +
> + i = 0;
> + list_for_each_entry_safe(entry, tmp, sorted_tasks, sorted_list) {
> + if (i < MAX_MONITORED_PIDS)
> + continue;
> + list_del_init(&entry->sorted_list);
> +
Ditto. Unnecessary new line.
> + }
Reading this function was not very easy for me. Adding more comments making te
code simpler would be nice.
> +}
> +
> +static struct damos *damon_dynamic_hotpages_new_scheme(int min_access,
> + enum damos_action action)
> +{
> + struct damos_access_pattern pattern = {
> + /* Find regions having PAGE_SIZE or larger size */
> + .min_sz_region = PMD_SIZE,
> + .max_sz_region = ULONG_MAX,
> + /* and not accessed at all */
> + .min_nr_accesses = min_access,
> + .max_nr_accesses = 100,
> + /* for min_age or more micro-seconds */
> + .min_age_region = 0,
> + .max_age_region = UINT_MAX,
Seems the comments aboe are not updated since copy-pasted.
> + };
> +
> + return damon_new_scheme(
> + &pattern,
> + /* synchrounous partial collapse as soon as found */
> + action, 0,
> + /* under the quota. */
> + &damon_dynamic_hotpages_quota,
> + /* (De)activate this according to the watermarks. */
> + &damon_dynamic_hotpages_wmarks, NUMA_NO_NODE);
> +}
> +
> +static int damon_dynamic_hotpages_apply_parameters(
> + struct task_monitor_node *monitored_task,
> + int min_access,
> + enum damos_action action)
Seems the parameters can be better aligned.
> +{
> + struct damos *scheme;
> + struct damon_ctx *param_ctx;
> + struct damon_target *param_target;
> + struct damos_filter *filter;
> + struct pid *spid;
> + int err;
> +
> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
> + DAMON_OPS_VADDR);
> + if (err)
> + return err;
> +
> + err = -EINVAL;
> + spid = find_get_pid(monitored_task->pid);
> + if (!spid) {
> + put_pid(spid);
You don't need to call put_pid() when get_pid() failed.
> + goto out;
> + }
> +
> + param_target->pid = spid;
> +
> + err = damon_set_attrs(param_ctx, &damon_dynamic_hotpages_mon_attrs);
> + if (err)
> + goto out;
> +
> + err = -ENOMEM;
> + scheme = damon_dynamic_hotpages_new_scheme(min_access, action);
> + if (!scheme)
> + goto out;
> +
> + damon_set_schemes(param_ctx, &scheme, 1);
> +
> + filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false);
> + if (!filter)
> + goto out;
> + damos_add_filter(scheme, filter);
> +
> + err = damon_commit_ctx(monitored_task->ctx, param_ctx);
> +out:
> + damon_destroy_ctx(param_ctx);
> + return err;
> +}
> +
> +static int damon_dynamic_hotpages_damon_call_fn(void *arg)
> +{
> + struct task_monitor_node *monitored_task = arg;
> + struct damon_ctx *ctx = monitored_task->ctx;
> + struct damos *scheme;
> + int err = 0;
> + int min_access;
> + struct damos_stat stat;
> +
> + damon_for_each_scheme(scheme, ctx)
> + stat = scheme->stat;
> + scheme = list_first_entry(&ctx->schemes, struct damos, list);
> +
> + if (ctx->passed_sample_intervals < scheme->next_apply_sis)
> + return err;
> +
> + if (stat.nr_applied)
> + return err;
> +
> + min_access = scheme->pattern.min_nr_accesses;
> +
> + if (min_access > HIGH_ACC_THRESHOLD) {
> + min_access = min_access - 10;
> + err = damon_dynamic_hotpages_apply_parameters(
> + monitored_task, min_access, DAMOS_COLLAPSE);
> + } else if (min_access > MID_ACC_THRESHOLD) {
> + min_access = min_access - 5;
> + err = damon_dynamic_hotpages_apply_parameters(
> + monitored_task, min_access, DAMOS_COLLAPSE);
> + } else if (min_access > LOW_ACC_THRESHOLD) {
> + min_access = min_access - 1;
> + err = damon_dynamic_hotpages_apply_parameters(
> + monitored_task, min_access, DAMOS_COLLAPSE);
> + }
> + return err;
> +}
> +
> +static int damon_dynamic_hotpages_init_task(
> + struct task_monitor_node *task_monitor)
You ain't need that many tabs.
> +{
> + int err = 0;
> + struct pid *spid;
> + struct damon_ctx *ctx = task_monitor->ctx;
> + struct damon_target *target = task_monitor->target;
> +
> + if (!ctx || !target)
> + damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_VADDR);
> +
> + if (ctx->kdamond)
> + return 0;
Please use damon_is_running() instead.
> +
> + spid = find_get_pid(task_monitor->pid);
> + if (!spid) {
> + put_pid(spid);
You don't need to call put_pid() with NULL.
> + return -ESRCH;
> + }
> +
> + target->pid = spid;
> +
> + if (err)
> + return err;
> +
> + task_monitor->call_control.fn = damon_dynamic_hotpages_damon_call_fn;
> + task_monitor->call_control.repeat = true;
> + task_monitor->call_control.data = task_monitor;
> +
> + struct damos *scheme =
> + damon_dynamic_hotpages_new_scheme(HIGHEST_MIN_ACCESS, DAMOS_COLLAPSE);
Please break the line for keeping the 80 columns limit.
> + if (!scheme)
> + return -ENOMEM;
> +
> + damon_set_schemes(ctx, &scheme, 1);
> +
> + task_monitor->ctx = ctx;
> + err = damon_start(&task_monitor->ctx, 1, false);
> + if (err)
> + return err;
> +
> + return damon_call(task_monitor->ctx, &task_monitor->call_control);
> +}
> +
> +static int add_monitored_task(struct task_struct *task,
> + struct list_head *task_monitor)
Too many tabs.
> +{
> + struct task_struct *thread;
> + struct task_monitor_node *task_node;
> + u64 total_time = 0;
> +
> + task_node = kzalloc(sizeof(struct task_monitor_node), GFP_KERNEL);
It is more conventional to do like below:
kzalloc(sizeof(*task_node), GFP_KERNEL);
> + if (!task_node)
> + return -ENOMEM;
> +
> + INIT_LIST_HEAD(&task_node->list);
> + INIT_LIST_HEAD(&task_node->sorted_list);
> + INIT_LIST_HEAD(&task_node->active_monitoring);
> +
> + task_node->min_access = HIGHEST_MIN_ACCESS;
> + task_node->pid = task_pid_nr(task);
> +
> + list_add_tail(&task_node->list, task_monitor);
> +
> + for_each_thread(task, thread)
> + total_time += thread->utime;
> +
> + task_node->previous_utime = total_time;
> + return 0;
> +}
> +
> +static int damon_dynamic_hotpages_attach_tasks(
> + struct list_head *task_monitor_sorted,
> + struct list_head *task_monitor_active)
Too much indents.
> +{
> + struct task_monitor_node *sorted_task_node, *tmp;
> + int err;
> + int i = 0;
> +
> + sorted_task_node = list_first_entry(
> + task_monitor_sorted, struct task_monitor_node, sorted_list);
> + while (i < MAX_MONITORED_PIDS && !list_entry_is_head(sorted_task_node,
> + task_monitor_sorted, sorted_list)) {
> + if (sorted_task_node->ctx && sorted_task_node->ctx->kdamond)
> + list_move(&sorted_task_node->active_monitoring,
> + task_monitor_active);
> + else {
> + rcu_read_lock();
> + if (!find_vpid(sorted_task_node->pid)) {
> + sorted_task_node->ctx = NULL;
> + sorted_task_node = list_next_entry(
> + sorted_task_node, sorted_list);
> +
> + rcu_read_unlock();
> + continue;
> + }
> + rcu_read_unlock();
> +
> + err = damon_dynamic_hotpages_init_task(sorted_task_node);
> + if (err) {
> + sorted_task_node->ctx = NULL;
> + sorted_task_node = list_next_entry(
> + sorted_task_node, sorted_list);
> + continue;
> + }
> +
> + list_add(&sorted_task_node->active_monitoring,
> + task_monitor_active);
> + }
> +
> + monitored_pids[i] = sorted_task_node->pid;
> + sorted_task_node = list_next_entry(sorted_task_node, sorted_list);
> +
> + i++;
> + }
> +
> + i = 0;
> + list_for_each_entry_safe(sorted_task_node, tmp, task_monitor_active,
> + active_monitoring) {
> + if (i < MAX_MONITORED_PIDS) {
> + i++;
> + continue;
> + }
> +
> + if (sorted_task_node->ctx) {
> + damon_stop(&sorted_task_node->ctx, 1);
> + damon_destroy_ctx(sorted_task_node->ctx);
> + sorted_task_node->ctx = NULL;
> + }
> +
> + list_del_init(&sorted_task_node->active_monitoring);
> + }
> + return 0;
> +}
This is bit difficult to read. Adding more comments and refactoring to be
easier to read would be nice.
And similar comments would be applied to below. I understand this patch series
is intentionally not very cleanly wrote, as this is an RFC for high level
concept. I therefore left comments for only things that immediately standing
out to me. If my understanding is not wrong, I will do more detailed review of
code in the next version of this patch series.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module
2026-02-02 14:56 ` [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module gutierrez.asier
@ 2026-02-03 5:34 ` SeongJae Park
0 siblings, 0 replies; 22+ messages in thread
From: SeongJae Park @ 2026-02-03 5:34 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
Let's use "Docs/admin-guide/mm/damon:" as the prefix of the commit subject.
On Mon, 2 Feb 2026 14:56:49 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> Documentation for dynamic_hugepage DAMON module.
>
> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
> ---
> .../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++++++++++++++
> 1 file changed, 173 insertions(+)
>
> diff --git a/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst b/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
> new file mode 100644
> index 000000000000..a6afb0910661
> --- /dev/null
> +++ b/Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
[...]
> +How It Works?
> +=============
> +
> +DAMON_HOT_HUGEPAGE spawns a new kthread which will monitor the applications in
> +the system. The monitor thread will calculate the moving average of the sum of
> +utimes of all the threads for all the processes. Then, pick the top three and
> +launch a damon process to monitor the hot regions in those tasks.
> +
> +Since we don't know the minaccess number in advance, we set it to 90 initially,
minaccess number -> optimum value of the min_nr_accesses value ?
[...]
> +Example
> +=======
> +Below runtime example commands make DAMON_HOT_HUGEPAGE to find memory regions in
> +the 3 most active tasks. It also asks DAMON_HOT_HUGEPAGE to do nothing if the
> +system's free memory rate is more than 50%, but start the real works if it
> +becomes lower than 40%.
> +
> + # cd /sys/module/damon_dynamic_hotpages/parameters/
> + # echo 10 > quota_ms
> + # echo 1000 > quota_reset_interval_ms
> + # echo 500 > wmarks_high
> + # echo 400 > wmarks_mid
> + # echo 200 > wmarks_low
> + # echo Y > enabled
> \ No newline at end of file
Please generously give a new line ;)
My high line comments including name of the module, the expected use case of
the watermarks also apply above. Same to my comment on the third patch of this
series, I will do more detailed review of this patch again on the next
version, since I presume the high level idea discussion is the main goal of
this series. Correct me if I'm wrong.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-03 1:10 ` [RFC PATCH v1 0/4] mm/damon: Support hot application detections SeongJae Park
@ 2026-02-03 13:03 ` Gutierrez Asier
2026-02-04 7:31 ` SeongJae Park
2026-02-03 14:25 ` Gutierrez Asier
1 sibling, 1 reply; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-03 13:03 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
Hi SeongJae!
On 2/3/2026 4:10 AM, SeongJae Park wrote:
> Hello Asier,
>
>
> Thank you for sharing this nice RFC patch series!
>
> On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> Overview
>> ----------
>>
>> This patch set introduces a new dynamic mechanism for detecting hot applications
>> and hot regions in those applications.
>>
>> Motivation
>> -----------
>>
>> Currently DAMON requires the system administrator to provide information about
>> which application needs to be monitored and all the parameters. Ideally this
>> should be done automatically, with minimal intervention from the system
>> administrator.
>>
>>
>> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
>> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
>> fragmentation and memory waste. For this reason, most application guides and
>> system administrators suggest to disable THP.
>>
>> We would like to detect: 1. which applications are hot in the system and 2.
>> which memory regions are hot in order to collapse those regions.
>>
>>
>> Solution
>> -----------
>>
>> ┌────────────┐ ┌────────────┐
>> │Damon_module│ │Task_monitor│
>> └──────┬─────┘ └──────┬─────┘
>> │ start │
>> │───────────────────────>│
>> │ │
>> │ │────┐
>> │ │ │ calculate task load
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ sort tasks
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ start kdamond for top 3 tasks
>> │ │<───┘
>> ┌──────┴─────┐ ┌──────┴─────┐
>> │Damon_module│ │Task_monitor│
>> └────────────┘ └────────────┘
>>
>>
>> We calculate the task load base on the sum of all the utime for all the threads
>> in a given task. Once we get total utime, we use the exponential load average
>> provided by calc_load. The tasks that become cold, the kdamond will be stopped
>> for them.
>
> Sounds interesting, and this high level idea makes sense to me. :)
>
> I'd like to further learn a few things. Is there a reason to think the top 3
> tasks are enough number of tasks? Also, what if a region was hot and
> successfully promoted to use huge pages, but later be cold? Should we also
> have a DAMOS scheme for splitting such no-more-hot huge pages?
No specific reason. This was just for the RFC. We could move this to a parameter
somehow.
In case of a region turning cold, I haven't worked on it. In turning hot means
that we collapse the hot region, we should do the opposite (split) in case the
area turns cold. I haven't thought about it, but that a good catch. Thanks!
>>
>> In each kdamond, we start with a high min_access value. Our goal is to find the
>> "maximum" min_access value at which point the DAMON action is applied. In each
>> cycle, if no action is applied, we lower the min_access.
>
> Sounds like a nice auto-tuning. And we have DAMOS quota goal for that kind of
> auto-tuning. Have you considered using that?
>
>>
>> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
>> collapse synchronously and avoid polluting khugepaged and other parts of the MM
>> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
>> which needs the correct vm_flags_t set.
>>
>> Benchmark
>> -----------
>
> Seems you forgot writing this section up. Or, you don't have benchmark results
> yet, but only mistakenly wrote the above section header? Either is fine, as
> this is just an RFC. Nevertheless, test results and your expected use case of
> this patch series will be very helpful.
>
>
> Thanks,
> SJ
>
> [...]
>
Sure, will add the benchmark results in the next RFC version.
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules
2026-02-03 1:16 ` SeongJae Park
@ 2026-02-03 13:04 ` Gutierrez Asier
0 siblings, 0 replies; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-03 13:04 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
On 2/3/2026 4:16 AM, SeongJae Park wrote:
> Let's use 'mm/damon/modules-common:' as the commit subject prefix.
>
> On Mon, 2 Feb 2026 14:56:46 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> Damon_modules_new_paddr_ctx_target. This works only for physical contexts.
>
> Let's be case-sensitive. s/Damon_/damon_/ ?
OK, will do it.
>
>> In case of virtual addresses, we should duplicate the code.
>>
>> It is more elegant to have a generic version of new context creation which
>> receives the mode as a parameter.
>
> Makes sense to me.
>
>>
>> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
>> ---
>> mm/damon/lru_sort.c | 6 ++++--
>> mm/damon/modules-common.c | 7 ++++---
>> mm/damon/modules-common.h | 5 +++--
>> mm/damon/reclaim.c | 5 +++--
>> 4 files changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
>> index 49b4bc294f4e..ac34b02dace8 100644
>> --- a/mm/damon/lru_sort.c
>> +++ b/mm/damon/lru_sort.c
>> @@ -201,7 +201,8 @@ static int damon_lru_sort_apply_parameters(void)
>> unsigned int hot_thres, cold_thres;
>> int err;
>>
>> - err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
>> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
>> + DAMON_OPS_PADDR);
>> if (err)
>> return err;
>>
>> @@ -375,7 +376,8 @@ static int __init damon_lru_sort_init(void)
>> err = -ENOMEM;
>> goto out;
>> }
>> - err = damon_modules_new_paddr_ctx_target(&ctx, &target);
>> + err = damon_modules_new_ctx_target(&ctx, &target,
>> + DAMON_OPS_PADDR);
>
> You could put the above line on the line before that without violating the 80
> columns limit :)
Sure, will correct it.
>
>> if (err)
>> goto out;
>>
>> diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c
>> index 86d58f8c4f63..5ba24e0ad9a1 100644
>> --- a/mm/damon/modules-common.c
>> +++ b/mm/damon/modules-common.c
>> @@ -14,8 +14,9 @@
>> * @ctxp: Pointer to save the point to the newly created context
>> * @targetp: Pointer to save the point to the newly created target
>> */
>> -int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
>> - struct damon_target **targetp)
>> +int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
>> + struct damon_target **targetp,
>> + enum damon_ops_id mode)
>
> You should also update the kernel-doc comments for the new parameter.
>
>> {
>> struct damon_ctx *ctx;
>> struct damon_target *target;
>> @@ -24,7 +25,7 @@ int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
>> if (!ctx)
>> return -ENOMEM;
>>
>> - if (damon_select_ops(ctx, DAMON_OPS_PADDR)) {
>> + if (damon_select_ops(ctx, mode)) {
>> damon_destroy_ctx(ctx);
>> return -EINVAL;
>> }
>> diff --git a/mm/damon/modules-common.h b/mm/damon/modules-common.h
>> index f103ad556368..87d8058d7d85 100644
>> --- a/mm/damon/modules-common.h
>> +++ b/mm/damon/modules-common.h
>> @@ -45,5 +45,6 @@
>> module_param_named(nr_##qt_exceed_name, stat.qt_exceeds, ulong, \
>> 0400);
>>
>> -int damon_modules_new_paddr_ctx_target(struct damon_ctx **ctxp,
>> - struct damon_target **targetp);
>> +int damon_modules_new_ctx_target(struct damon_ctx **ctxp,
>> + struct damon_target **targetp,
>> + enum damon_ops_id mode);
>> diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
>> index 36a582e09eae..b64fb810e096 100644
>> --- a/mm/damon/reclaim.c
>> +++ b/mm/damon/reclaim.c
>> @@ -197,7 +197,8 @@ static int damon_reclaim_apply_parameters(void)
>> struct damos_filter *filter;
>> int err;
>>
>> - err = damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target);
>> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
>> + DAMON_OPS_PADDR);
>> if (err)
>> return err;
>>
>> @@ -379,7 +380,7 @@ static int __init damon_reclaim_init(void)
>> err = -ENOMEM;
>> goto out;
>> }
>> - err = damon_modules_new_paddr_ctx_target(&ctx, &target);
>> + err = damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_PADDR);
>> if (err)
>> goto out;
>>
>> --
>> 2.43.0
>
> Overall, looks good for RFC.
>
>
> Thanks,
> SJ
>
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse
2026-02-03 1:23 ` SeongJae Park
@ 2026-02-03 14:04 ` Gutierrez Asier
0 siblings, 0 replies; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-03 14:04 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
On 2/3/2026 4:23 AM, SeongJae Park wrote:
> On Mon, 2 Feb 2026 14:56:47 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> * Support for huge pages collapse, which will be used by
>> dynamic_hugepages module.
>>
>> * Include the new module for compilation
>>
>> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
>> ---
>> include/linux/damon.h | 1 +
>> mm/damon/Kconfig | 7 +++++++
>> mm/damon/Makefile | 1 +
>> mm/damon/vaddr.c | 3 +++
>> 4 files changed, 12 insertions(+)
>>
>> diff --git a/include/linux/damon.h b/include/linux/damon.h
>> index 3813373a9200..de5a994f92c2 100644
>> --- a/include/linux/damon.h
>> +++ b/include/linux/damon.h
>> @@ -142,6 +142,7 @@ enum damos_action {
>> DAMOS_LRU_DEPRIO,
>> DAMOS_MIGRATE_HOT,
>> DAMOS_MIGRATE_COLD,
>> + DAMOS_COLLAPSE,
>
> Please update the kernel-doc comments for this new action, by the time you drop
> the RFC tag from this patch series.
>
>> DAMOS_STAT, /* Do nothing but only record the stat */
>> NR_DAMOS_ACTIONS,
>> };
>> diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig
>> index 8c868f7035fc..2355aacb6d12 100644
>> --- a/mm/damon/Kconfig
>> +++ b/mm/damon/Kconfig
>> @@ -110,4 +110,11 @@ config DAMON_STAT_ENABLED_DEFAULT
>> Whether to enable DAMON_STAT by default. Users can disable it in
>> boot or runtime using its 'enabled' parameter.
>>
>> +config DAMON_HOT_HUGEPAGE
>> + bool "Build DAMON-based collapse of hot regions (DAMON_HOT_HUGEPAGES)"
>> + depends on DAMON_VADDR
>> + help
>> + Collapse hot region into huge pages. Hot regions are determined by
>> + DAMON-based sampling
>> +
>
> Apparently you wanted to introduce the above change on the next patch, but
> mistakenly added here?
>
> I'm also feeling the name might be better to be simpler. What about... say,
> just DAMON_HUGEPAGE? We might want to extend that for general access-aware
> huge pages.
I will move the build stuff into a different commit for the next RFC series.
I agree with the name change, I will do it.
>> endmenu
>> diff --git a/mm/damon/Makefile b/mm/damon/Makefile
>> index d8d6bf5f8bff..998bddc17819 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_HOT_HUGEPAGE) += modules-common.o dynamic_hugepages.o
>
> Ditto.
>
>> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
>> index 23ed738a0bd6..4acbc1a6a5be 100644
>> --- a/mm/damon/vaddr.c
>> +++ b/mm/damon/vaddr.c
>> @@ -970,6 +970,9 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
>> case DAMOS_NOHUGEPAGE:
>> madv_action = MADV_NOHUGEPAGE;
>> break;
>> + case DAMOS_COLLAPSE:
>> + madv_action = MADV_COLLAPSE;
>> + break;
>> case DAMOS_MIGRATE_HOT:
>> case DAMOS_MIGRATE_COLD:
>> return damos_va_migrate(t, r, scheme, sz_filter_passed);
>> --
>> 2.43.0
>
>
> Thanks,
> SJ
>
> [...]
>
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 3/4] mm/damon: New module with hot application detection
2026-02-03 5:04 ` SeongJae Park
@ 2026-02-03 14:21 ` Gutierrez Asier
0 siblings, 0 replies; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-03 14:21 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
On 2/3/2026 8:04 AM, SeongJae Park wrote:
> On Mon, 2 Feb 2026 14:56:48 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> This new module detects hot applications and launches a new kdamond
>> thread for each of them.
>>
>> 1. It first launches a new kthread called damon_dynamic.
>
> I feel like the name is bit ambiguous. What about something more specific to
> this module's use case, say, damon_hugepage_monitor or more shortly
> damon_hugepaged?
>
>> This thread
>> will monitor the tasks in the system by pooling. The tasks are sorted
>> by utime delta. For the top N tasks, a new kdamond thread will be
>> launched. Applications which turn cold will have their kdamond
>> stopped.
>>
>> 2. Initially we don't know the min_access for each of the task. We
>> want to find the highest min_access when collapses start happening.
>> For that we have an initial threashold of 90, which we will lower
>> until a collpase occurs.
>
> As I asked to the cover letter, I'm curious if you considered using DAMOS quota
> goal. Let's continue the discussion on the cover letter, though.
>
>>
>> Signed-off-by: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>> Co-developed-by: Anatoly Stepanov <stepanov.anatoly@huawei.com>
>> ---
>> mm/damon/dynamic_hugepages.c (new) | 579 +++++++++++++++++++++++++++++
>> 1 file changed, 579 insertions(+)
>>
>> diff --git a/mm/damon/dynamic_hugepages.c b/mm/damon/dynamic_hugepages.c
>
> I think the file name could be simpler, say, hugepage.c ?
Will do it.
>> new file mode 100644
>> index 000000000000..8b7c1e4d5840
>> --- /dev/null
>> +++ b/mm/damon/dynamic_hugepages.c
>> @@ -0,0 +1,579 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2025 HUAWEI, Inc.
>
> Captain, it's 2026! :)
Oops, my bad. Good catch.
>
>> + * https://www.huawei.com
>> + *
>> + * Author: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>> + */
>> +
>> +#define pr_fmt(fmt) "damon-dynamic-hotpages: " fmt
>
> Again, I'd prefer simpler one, like, "damon-hugepage: "
Same as the previous one, I will change it.
>
>> +
>> +#include <linux/damon.h>
>> +#include <linux/kstrtox.h>
>> +#include <linux/list_sort.h>
>> +#include <linux/module.h>
>> +#include <linux/sched/loadavg.h>
>> +
>> +#include "modules-common.h"
>> +
>> +#ifdef MODULE_PARAM_PREFIX
>> +#undef MODULE_PARAM_PREFIX
>> +#endif
>> +#define MODULE_PARAM_PREFIX "damon_dynamic_hotpages."
>
> Ditto. Maybe "damon_hugepage."
OK
>
>> +
>> +#define MAX_MONITORED_PIDS 3
>> +#define HIGHEST_MIN_ACCESS 90
>> +#define HIGH_ACC_THRESHOLD 50
>> +#define MID_ACC_THRESHOLD 15
>> +#define LOW_ACC_THRESHOLD 2
>> +
>> +static struct task_struct *monitor_thread;
>> +
>> +struct mutex enable_disable_lock;
>> +
>> +/*
>> + * Enable or disable DAMON_HOT_HUGEPAGE.
>> + *
>> + * You can enable DAMON_HOT_HUGEPAGE by setting the value of this parameter
>> + * as ``Y``. Setting it as ``N`` disables DAMON_HOT_HUGEPAGE. Note that
>> + * DAMON_HOT_HUGEPAGE could do no real monitoring and reclamation due to the
>> + * watermarks-based activation condition. Refer to below descriptions for the
>> + * watermarks parameter for this.
>
> Do you willing to use watermarks? Can you further explain how you will use it
> in your use case?
Maybe I have not done it correctly. The idea was for the module to run
every 5 seconds. Watermarks are used to create a new scheme and avoid
wasted cycles, running once and sleeping for 5 seconds. In my tests I
have not changed the settings. Maybe this comment doesn't reflect my
intetion. I will amend it.
>> + */
>> +static bool enabled __read_mostly;
>> +
>> +/*
>> + * DAMON_HOT_HUGEPAGE monitoring period.
>> + */
>> +static unsigned long monitor_period __read_mostly = 5000000;
>> +module_param(monitor_period, ulong, 0600);
>
> What is the time unit of this parameter? Documenting it would be nice.
I will comment this.
>> +
>> +static long monitored_pids[MAX_MONITORED_PIDS];
>> +module_param_array(monitored_pids, long, NULL, 0400);
>> +
>> +static int damon_dynamic_hotpages_turn(bool on);
>
> Seems the above declaration is not really needed?
>
>> +
>> +static struct damos_quota damon_dynamic_hotpages_quota = {
>> + /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */
>> + .ms = 10,
>> + .sz = 0,
>> + .reset_interval = 1000,
>> + /* Within the quota, page out older regions first. */
>
> You don't page out, but collapse, right? The coment may need to be updated.
>
>> + .weight_sz = 0,
>> + .weight_nr_accesses = 0,
>> + .weight_age = 1
>> +};
>> +DEFINE_DAMON_MODULES_DAMOS_TIME_QUOTA(damon_dynamic_hotpages_quota);
>> +
>> +static struct damos_watermarks damon_dynamic_hotpages_wmarks = {
>> + .metric = DAMOS_WMARK_FREE_MEM_RATE,
>> + .interval = 5000000, /* 5 seconds */
>> + .high = 900, /* 90 percent */
>> + .mid = 800, /* 80 percent */
>> + .low = 50, /* 5 percent */
>> +};
>> +DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_dynamic_hotpages_wmarks);
>
> What's the point of setting watermarks here, in hugepage use case?
As mentioned above, in my tests I have not changed the settings. Maybe
I can remove this line here.
>
>> +
>> +static struct damon_attrs damon_dynamic_hotpages_mon_attrs = {
>> + .sample_interval = 5000, /* 5 ms */
>> + .aggr_interval = 100000, /* 100 ms */
>
> This means nr_accesses of each region can be only up to 20 (100ms / 5ms).
> IIUC, you are auto-tuning the DAMOS target access pattern's min_nr_accesses
> starting from 90. If I'm not wrong, you may better to start from 20.
>
>> + .ops_update_interval = 0,
>> + .min_nr_regions = 10,
>> + .max_nr_regions = 1000,
>> +};
>> +DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_dynamic_hotpages_mon_attrs);
>> +
>> +struct task_monitor_node {
>> + pid_t pid;
>> +
>> + struct damon_ctx *ctx;
>> + struct damon_target *target;
>> + struct damon_call_control call_control;
>> + u64 previous_utime;
>> + unsigned long load;
>> + struct damos_stat stat;
>> + int min_access;
>> +
>> + struct list_head list;
>> + struct list_head sorted_list;
>> + struct list_head active_monitoring;
>> +};
>> +
>> +static void find_top_n(struct list_head *task_monitor,
>> + struct list_head *sorted_tasks)
>
> You ain't need to put that much tabs on the above line.
I will correct it. Thank!
>
>> +{
>> + struct task_monitor_node *entry, *to_test, *tmp;
>> + struct list_head *pos;
>> + int i;
>> +
>> + list_for_each_entry(entry, task_monitor, list) {
>> + i = 0;
>> + list_for_each(pos, sorted_tasks) {
>> + i++;
>> + to_test = list_entry(pos, struct task_monitor_node, sorted_list);
>
> I'd recommend to use list_for_each_entry() here, if possible.
OK, I will change it.
>
>> +
>> + if (entry->load > to_test->load) {
>> + list_add_tail(&entry->sorted_list, pos);
>> +
>
> The above new line seems unnecessary.
I will remove it.
>
>> + i = MAX_MONITORED_PIDS;
>> + }
>> +
>> + if (i == MAX_MONITORED_PIDS)
>> + break;
>> + }
>> +
>> + if (i < MAX_MONITORED_PIDS)
>> + list_add_tail(&entry->sorted_list, sorted_tasks);
>> + }
>> +
>> + i = 0;
>> + list_for_each_entry_safe(entry, tmp, sorted_tasks, sorted_list) {
>> + if (i < MAX_MONITORED_PIDS)
>> + continue;
>> + list_del_init(&entry->sorted_list);
>> +
>
> Ditto. Unnecessary new line.
Same as before.
>
>> + }
>
> Reading this function was not very easy for me. Adding more comments making te
> code simpler would be nice.
Sure, I will comment it.
>
>> +}
>> +
>> +static struct damos *damon_dynamic_hotpages_new_scheme(int min_access,
>> + enum damos_action action)
>> +{
>> + struct damos_access_pattern pattern = {
>> + /* Find regions having PAGE_SIZE or larger size */
>> + .min_sz_region = PMD_SIZE,
>> + .max_sz_region = ULONG_MAX,
>> + /* and not accessed at all */
>> + .min_nr_accesses = min_access,
>> + .max_nr_accesses = 100,
>> + /* for min_age or more micro-seconds */
>> + .min_age_region = 0,
>> + .max_age_region = UINT_MAX,
>
> Seems the comments aboe are not updated since copy-pasted.
Same, I will rework it.
>
>> + };
>> +
>> + return damon_new_scheme(
>> + &pattern,
>> + /* synchrounous partial collapse as soon as found */
>> + action, 0,
>> + /* under the quota. */
>> + &damon_dynamic_hotpages_quota,
>> + /* (De)activate this according to the watermarks. */
>> + &damon_dynamic_hotpages_wmarks, NUMA_NO_NODE);
>> +}
>> +
>> +static int damon_dynamic_hotpages_apply_parameters(
>> + struct task_monitor_node *monitored_task,
>> + int min_access,
>> + enum damos_action action)
>
> Seems the parameters can be better aligned.
OK.
>
>> +{
>> + struct damos *scheme;
>> + struct damon_ctx *param_ctx;
>> + struct damon_target *param_target;
>> + struct damos_filter *filter;
>> + struct pid *spid;
>> + int err;
>> +
>> + err = damon_modules_new_ctx_target(¶m_ctx, ¶m_target,
>> + DAMON_OPS_VADDR);
>> + if (err)
>> + return err;
>> +
>> + err = -EINVAL;
>> + spid = find_get_pid(monitored_task->pid);
>> + if (!spid) {
>> + put_pid(spid);
>
> You don't need to call put_pid() when get_pid() failed.
Yeap, my bad, I will remove it.
>
>> + goto out;
>> + }
>> +
>> + param_target->pid = spid;
>> +
>> + err = damon_set_attrs(param_ctx, &damon_dynamic_hotpages_mon_attrs);
>> + if (err)
>> + goto out;
>> +
>> + err = -ENOMEM;
>> + scheme = damon_dynamic_hotpages_new_scheme(min_access, action);
>> + if (!scheme)
>> + goto out;
>> +
>> + damon_set_schemes(param_ctx, &scheme, 1);
>> +
>> + filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false);
>> + if (!filter)
>> + goto out;
>> + damos_add_filter(scheme, filter);
>> +
>> + err = damon_commit_ctx(monitored_task->ctx, param_ctx);
>> +out:
>> + damon_destroy_ctx(param_ctx);
>> + return err;
>> +}
>> +
>> +static int damon_dynamic_hotpages_damon_call_fn(void *arg)
>> +{
>> + struct task_monitor_node *monitored_task = arg;
>> + struct damon_ctx *ctx = monitored_task->ctx;
>> + struct damos *scheme;
>> + int err = 0;
>> + int min_access;
>> + struct damos_stat stat;
>> +
>> + damon_for_each_scheme(scheme, ctx)
>> + stat = scheme->stat;
>> + scheme = list_first_entry(&ctx->schemes, struct damos, list);
>> +
>> + if (ctx->passed_sample_intervals < scheme->next_apply_sis)
>> + return err;
>> +
>> + if (stat.nr_applied)
>> + return err;
>> +
>> + min_access = scheme->pattern.min_nr_accesses;
>> +
>> + if (min_access > HIGH_ACC_THRESHOLD) {
>> + min_access = min_access - 10;
>> + err = damon_dynamic_hotpages_apply_parameters(
>> + monitored_task, min_access, DAMOS_COLLAPSE);
>> + } else if (min_access > MID_ACC_THRESHOLD) {
>> + min_access = min_access - 5;
>> + err = damon_dynamic_hotpages_apply_parameters(
>> + monitored_task, min_access, DAMOS_COLLAPSE);
>> + } else if (min_access > LOW_ACC_THRESHOLD) {
>> + min_access = min_access - 1;
>> + err = damon_dynamic_hotpages_apply_parameters(
>> + monitored_task, min_access, DAMOS_COLLAPSE);
>> + }
>> + return err;
>> +}
>> +
>> +static int damon_dynamic_hotpages_init_task(
>> + struct task_monitor_node *task_monitor)
>
> You ain't need that many tabs.
>
>> +{
>> + int err = 0;
>> + struct pid *spid;
>> + struct damon_ctx *ctx = task_monitor->ctx;
>> + struct damon_target *target = task_monitor->target;
>> +
>> + if (!ctx || !target)
>> + damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_VADDR);
>> +
>> + if (ctx->kdamond)
>> + return 0;
>
> Please use damon_is_running() instead.
OK.
>
>> +
>> + spid = find_get_pid(task_monitor->pid);
>> + if (!spid) {
>> + put_pid(spid);
>
> You don't need to call put_pid() with NULL.
OK.
>
>> + return -ESRCH;
>> + }
>> +
>> + target->pid = spid;
>> +
>> + if (err)
>> + return err;
>> +
>> + task_monitor->call_control.fn = damon_dynamic_hotpages_damon_call_fn;
>> + task_monitor->call_control.repeat = true;
>> + task_monitor->call_control.data = task_monitor;
>> +
>> + struct damos *scheme =
>> + damon_dynamic_hotpages_new_scheme(HIGHEST_MIN_ACCESS, DAMOS_COLLAPSE);
>
> Please break the line for keeping the 80 columns limit.
Sure.
>
>> + if (!scheme)
>> + return -ENOMEM;
>> +
>> + damon_set_schemes(ctx, &scheme, 1);
>> +
>> + task_monitor->ctx = ctx;
>> + err = damon_start(&task_monitor->ctx, 1, false);
>> + if (err)
>> + return err;
>> +
>> + return damon_call(task_monitor->ctx, &task_monitor->call_control);
>> +}
>> +
>> +static int add_monitored_task(struct task_struct *task,
>> + struct list_head *task_monitor)
>
> Too many tabs.
I will update it.
>
>> +{
>> + struct task_struct *thread;
>> + struct task_monitor_node *task_node;
>> + u64 total_time = 0;
>> +
>> + task_node = kzalloc(sizeof(struct task_monitor_node), GFP_KERNEL);
>
> It is more conventional to do like below:
>
> kzalloc(sizeof(*task_node), GFP_KERNEL);
OK, I will change it.
>
>> + if (!task_node)
>> + return -ENOMEM;
>> +
>> + INIT_LIST_HEAD(&task_node->list);
>> + INIT_LIST_HEAD(&task_node->sorted_list);
>> + INIT_LIST_HEAD(&task_node->active_monitoring);
>> +
>> + task_node->min_access = HIGHEST_MIN_ACCESS;
>> + task_node->pid = task_pid_nr(task);
>> +
>> + list_add_tail(&task_node->list, task_monitor);
>> +
>> + for_each_thread(task, thread)
>> + total_time += thread->utime;
>> +
>> + task_node->previous_utime = total_time;
>> + return 0;
>> +}
>> +
>> +static int damon_dynamic_hotpages_attach_tasks(
>> + struct list_head *task_monitor_sorted,
>> + struct list_head *task_monitor_active)
>
> Too much indents.
OK.
>
>> +{
>> + struct task_monitor_node *sorted_task_node, *tmp;
>> + int err;
>> + int i = 0;
>> +
>> + sorted_task_node = list_first_entry(
>> + task_monitor_sorted, struct task_monitor_node, sorted_list);
>> + while (i < MAX_MONITORED_PIDS && !list_entry_is_head(sorted_task_node,
>> + task_monitor_sorted, sorted_list)) {
>> + if (sorted_task_node->ctx && sorted_task_node->ctx->kdamond)
>> + list_move(&sorted_task_node->active_monitoring,
>> + task_monitor_active);
>> + else {
>> + rcu_read_lock();
>> + if (!find_vpid(sorted_task_node->pid)) {
>> + sorted_task_node->ctx = NULL;
>> + sorted_task_node = list_next_entry(
>> + sorted_task_node, sorted_list);
>> +
>> + rcu_read_unlock();
>> + continue;
>> + }
>> + rcu_read_unlock();
>> +
>> + err = damon_dynamic_hotpages_init_task(sorted_task_node);
>> + if (err) {
>> + sorted_task_node->ctx = NULL;
>> + sorted_task_node = list_next_entry(
>> + sorted_task_node, sorted_list);
>> + continue;
>> + }
>> +
>> + list_add(&sorted_task_node->active_monitoring,
>> + task_monitor_active);
>> + }
>> +
>> + monitored_pids[i] = sorted_task_node->pid;
>> + sorted_task_node = list_next_entry(sorted_task_node, sorted_list);
>> +
>> + i++;
>> + }
>> +
>> + i = 0;
>> + list_for_each_entry_safe(sorted_task_node, tmp, task_monitor_active,
>> + active_monitoring) {
>> + if (i < MAX_MONITORED_PIDS) {
>> + i++;
>> + continue;
>> + }
>> +
>> + if (sorted_task_node->ctx) {
>> + damon_stop(&sorted_task_node->ctx, 1);
>> + damon_destroy_ctx(sorted_task_node->ctx);
>> + sorted_task_node->ctx = NULL;
>> + }
>> +
>> + list_del_init(&sorted_task_node->active_monitoring);
>> + }
>> + return 0;
>> +}
>
> This is bit difficult to read. Adding more comments and refactoring to be
> easier to read would be nice.
>
> And similar comments would be applied to below. I understand this patch series
> is intentionally not very cleanly wrote, as this is an RFC for high level
> concept. I therefore left comments for only things that immediately standing
> out to me. If my understanding is not wrong, I will do more detailed review of
> code in the next version of this patch series.
>
>
> Thanks,
> SJ
>
> [...]
>
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-03 1:10 ` [RFC PATCH v1 0/4] mm/damon: Support hot application detections SeongJae Park
2026-02-03 13:03 ` Gutierrez Asier
@ 2026-02-03 14:25 ` Gutierrez Asier
2026-02-04 7:17 ` SeongJae Park
1 sibling, 1 reply; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-03 14:25 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
SeongJae,
Thanks a lot for all the useful feedback.
One thing that I was not sure about while working on this patch set
is whether to have an external new module or adding the logic to
damon core. I mean, the hot application detecting can be useful for
all other modules and can improve DAMON performance. What do you think?
My implementation was module based because I tried to avoid changes
to DAMON core for the RFC.
On 2/3/2026 4:10 AM, SeongJae Park wrote:
> Hello Asier,
>
>
> Thank you for sharing this nice RFC patch series!
>
> On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> Overview
>> ----------
>>
>> This patch set introduces a new dynamic mechanism for detecting hot applications
>> and hot regions in those applications.
>>
>> Motivation
>> -----------
>>
>> Currently DAMON requires the system administrator to provide information about
>> which application needs to be monitored and all the parameters. Ideally this
>> should be done automatically, with minimal intervention from the system
>> administrator.
>>
>>
>> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
>> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
>> fragmentation and memory waste. For this reason, most application guides and
>> system administrators suggest to disable THP.
>>
>> We would like to detect: 1. which applications are hot in the system and 2.
>> which memory regions are hot in order to collapse those regions.
>>
>>
>> Solution
>> -----------
>>
>> ┌────────────┐ ┌────────────┐
>> │Damon_module│ │Task_monitor│
>> └──────┬─────┘ └──────┬─────┘
>> │ start │
>> │───────────────────────>│
>> │ │
>> │ │────┐
>> │ │ │ calculate task load
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ sort tasks
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ start kdamond for top 3 tasks
>> │ │<───┘
>> ┌──────┴─────┐ ┌──────┴─────┐
>> │Damon_module│ │Task_monitor│
>> └────────────┘ └────────────┘
>>
>>
>> We calculate the task load base on the sum of all the utime for all the threads
>> in a given task. Once we get total utime, we use the exponential load average
>> provided by calc_load. The tasks that become cold, the kdamond will be stopped
>> for them.
>
> Sounds interesting, and this high level idea makes sense to me. :)
>
> I'd like to further learn a few things. Is there a reason to think the top 3
> tasks are enough number of tasks? Also, what if a region was hot and
> successfully promoted to use huge pages, but later be cold? Should we also
> have a DAMOS scheme for splitting such no-more-hot huge pages?
>
>>
>> In each kdamond, we start with a high min_access value. Our goal is to find the
>> "maximum" min_access value at which point the DAMON action is applied. In each
>> cycle, if no action is applied, we lower the min_access.
>
> Sounds like a nice auto-tuning. And we have DAMOS quota goal for that kind of
> auto-tuning. Have you considered using that?
>
>>
>> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
>> collapse synchronously and avoid polluting khugepaged and other parts of the MM
>> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
>> which needs the correct vm_flags_t set.
>>
>> Benchmark
>> -----------
>
> Seems you forgot writing this section up. Or, you don't have benchmark results
> yet, but only mistakenly wrote the above section header? Either is fine, as
> this is just an RFC. Nevertheless, test results and your expected use case of
> this patch series will be very helpful.
>
>
> Thanks,
> SJ
>
> [...]
>
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-03 14:25 ` Gutierrez Asier
@ 2026-02-04 7:17 ` SeongJae Park
2026-02-04 13:07 ` Gutierrez Asier
0 siblings, 1 reply; 22+ messages in thread
From: SeongJae Park @ 2026-02-04 7:17 UTC (permalink / raw)
To: Gutierrez Asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Tue, 3 Feb 2026 17:25:11 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
> SeongJae,
>
> Thanks a lot for all the useful feedback.
The pleasure is mine! :)
>
> One thing that I was not sure about while working on this patch set
> is whether to have an external new module or adding the logic to
> damon core. I mean, the hot application detecting can be useful for
> all other modules and can improve DAMON performance.
All exising non-sample DAMON modules are working for the physical address
space. I hence finding no many opportunities to bring benefits of hot
application detection to those.
I agree the hot applications detection could be useful in general and creative
DAMON use cases for virtual address spaces. Implementing the feature in DAMON
core layer and exposing it via DAMON sysfs interface will help such use cases.
But it seems not straightforward to imagine how the sysfs interface can be
extended for the feature.
So, I think it would better to be implemented inside the new module at the
moment. Later, if we end up having more modules that use the feature, we could
move it to the modules-common or the core. If we further find a good way to
integrate that with sysfs interface, definitely it could go to core.
From this point, however, I realize the feature can also be implemented in the
user sapce in a pretty straightforward way. Have you considered that?
> What do you think?
> My implementation was module based because I tried to avoid changes
> to DAMON core for the RFC.
If there is a good reason to implement that not in the user space but the
kernel space, as I mentioned above, it seems the module is the right place to
me.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-03 13:03 ` Gutierrez Asier
@ 2026-02-04 7:31 ` SeongJae Park
0 siblings, 0 replies; 22+ messages in thread
From: SeongJae Park @ 2026-02-04 7:31 UTC (permalink / raw)
To: Gutierrez Asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Tue, 3 Feb 2026 16:03:04 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
> Hi SeongJae!
>
> On 2/3/2026 4:10 AM, SeongJae Park wrote:
> > Hello Asier,
> >
> >
> > Thank you for sharing this nice RFC patch series!
> >
> > On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> >
> >> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> >>
> >> Overview
> >> ----------
> >>
> >> This patch set introduces a new dynamic mechanism for detecting hot applications
> >> and hot regions in those applications.
> >>
> >> Motivation
> >> -----------
> >>
> >> Currently DAMON requires the system administrator to provide information about
> >> which application needs to be monitored and all the parameters. Ideally this
> >> should be done automatically, with minimal intervention from the system
> >> administrator.
> >>
> >>
> >> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
> >> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
> >> fragmentation and memory waste. For this reason, most application guides and
> >> system administrators suggest to disable THP.
> >>
> >> We would like to detect: 1. which applications are hot in the system and 2.
> >> which memory regions are hot in order to collapse those regions.
> >>
> >>
> >> Solution
> >> -----------
> >>
> >> ┌────────────┐ ┌────────────┐
> >> │Damon_module│ │Task_monitor│
> >> └──────┬─────┘ └──────┬─────┘
> >> │ start │
> >> │───────────────────────>│
> >> │ │
> >> │ │────┐
> >> │ │ │ calculate task load
> >> │ │<───┘
> >> │ │
> >> │ │────┐
> >> │ │ │ sort tasks
> >> │ │<───┘
> >> │ │
> >> │ │────┐
> >> │ │ │ start kdamond for top 3 tasks
> >> │ │<───┘
> >> ┌──────┴─────┐ ┌──────┴─────┐
> >> │Damon_module│ │Task_monitor│
> >> └────────────┘ └────────────┘
> >>
> >>
> >> We calculate the task load base on the sum of all the utime for all the threads
> >> in a given task. Once we get total utime, we use the exponential load average
> >> provided by calc_load. The tasks that become cold, the kdamond will be stopped
> >> for them.
> >
> > Sounds interesting, and this high level idea makes sense to me. :)
> >
> > I'd like to further learn a few things. Is there a reason to think the top 3
> > tasks are enough number of tasks? Also, what if a region was hot and
> > successfully promoted to use huge pages, but later be cold? Should we also
> > have a DAMOS scheme for splitting such no-more-hot huge pages?
>
> No specific reason. This was just for the RFC. We could move this to a parameter
> somehow.
Makes sense. Depending on the test results with 3 tasks default value, I think
we could just keep it a hard-coded default one. If it turns out it is not
working good for different cases, we could make it a tunable parameter or
internally auto-tuned.
>
> In case of a region turning cold, I haven't worked on it. In turning hot means
> that we collapse the hot region, we should do the opposite (split) in case the
> area turns cold. I haven't thought about it, but that a good catch. Thanks!
You're welcome!
>
> >>
> >> In each kdamond, we start with a high min_access value. Our goal is to find the
> >> "maximum" min_access value at which point the DAMON action is applied. In each
> >> cycle, if no action is applied, we lower the min_access.
> >
> > Sounds like a nice auto-tuning. And we have DAMOS quota goal for that kind of
> > auto-tuning. Have you considered using that?
Maybe you missed the above question?
> >
> >>
> >> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
> >> collapse synchronously and avoid polluting khugepaged and other parts of the MM
> >> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
> >> which needs the correct vm_flags_t set.
> >>
> >> Benchmark
> >> -----------
> >
> > Seems you forgot writing this section up. Or, you don't have benchmark results
> > yet, but only mistakenly wrote the above section header? Either is fine, as
> > this is just an RFC. Nevertheless, test results and your expected use case of
> > this patch series will be very helpful.
> >
> >
> > Thanks,
> > SJ
> >
> > [...]
> >
>
> Sure, will add the benchmark results in the next RFC version.
Looking forward! I'm particularly interested in your expected or planned use
case, including why you implement the top n processes logic inside the kernel
instead of putting it on the user space. I'm also interested in how well the
test setup is representing the realistic use case, and how good the results is.
That will help us deciding important things including whether this can be
merged, and if some corner cases handling should be made before or after
merging it, earlier.
Thanks,
SJ
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-04 7:17 ` SeongJae Park
@ 2026-02-04 13:07 ` Gutierrez Asier
2026-02-04 15:43 ` SeongJae Park
0 siblings, 1 reply; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-04 13:07 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
On 2/4/2026 10:17 AM, SeongJae Park wrote:
> On Tue, 3 Feb 2026 17:25:11 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
>
>> SeongJae,
>>
>> Thanks a lot for all the useful feedback.
>
> The pleasure is mine! :)
>
>>
>> One thing that I was not sure about while working on this patch set
>> is whether to have an external new module or adding the logic to
>> damon core. I mean, the hot application detecting can be useful for
>> all other modules and can improve DAMON performance.
>
> All exising non-sample DAMON modules are working for the physical address
> space. I hence finding no many opportunities to bring benefits of hot
> application detection to those.
>
> I agree the hot applications detection could be useful in general and creative
> DAMON use cases for virtual address spaces. Implementing the feature in DAMON
> core layer and exposing it via DAMON sysfs interface will help such use cases.
> But it seems not straightforward to imagine how the sysfs interface can be
> extended for the feature.
>
> So, I think it would better to be implemented inside the new module at the
> moment. Later, if we end up having more modules that use the feature, we could
> move it to the modules-common or the core. If we further find a good way to
> integrate that with sysfs interface, definitely it could go to core.
>
> From this point, however, I realize the feature can also be implemented in the
> user sapce in a pretty straightforward way. Have you considered that?
I though about it. However, accessing the task_struct directly and extracting
the utime is much more efficient that getting the required info from the user
space.
>
>> What do you think?
>> My implementation was module based because I tried to avoid changes
>> to DAMON core for the RFC.
>
> If there is a good reason to implement that not in the user space but the
> kernel space, as I mentioned above, it seems the module is the right place to
> me.
>
>
> Thanks,
> SJ
>
> [...]
>
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-04 13:07 ` Gutierrez Asier
@ 2026-02-04 15:43 ` SeongJae Park
0 siblings, 0 replies; 22+ messages in thread
From: SeongJae Park @ 2026-02-04 15:43 UTC (permalink / raw)
To: Gutierrez Asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Wed, 4 Feb 2026 16:07:40 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
>
>
> On 2/4/2026 10:17 AM, SeongJae Park wrote:
> > On Tue, 3 Feb 2026 17:25:11 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
> >
> >> SeongJae,
> >>
> >> Thanks a lot for all the useful feedback.
> >
> > The pleasure is mine! :)
> >
> >>
> >> One thing that I was not sure about while working on this patch set
> >> is whether to have an external new module or adding the logic to
> >> damon core. I mean, the hot application detecting can be useful for
> >> all other modules and can improve DAMON performance.
> >
> > All exising non-sample DAMON modules are working for the physical address
> > space. I hence finding no many opportunities to bring benefits of hot
> > application detection to those.
> >
> > I agree the hot applications detection could be useful in general and creative
> > DAMON use cases for virtual address spaces. Implementing the feature in DAMON
> > core layer and exposing it via DAMON sysfs interface will help such use cases.
> > But it seems not straightforward to imagine how the sysfs interface can be
> > extended for the feature.
> >
> > So, I think it would better to be implemented inside the new module at the
> > moment. Later, if we end up having more modules that use the feature, we could
> > move it to the modules-common or the core. If we further find a good way to
> > integrate that with sysfs interface, definitely it could go to core.
> >
> > From this point, however, I realize the feature can also be implemented in the
> > user sapce in a pretty straightforward way. Have you considered that?
>
> I though about it. However, accessing the task_struct directly and extracting
> the utime is much more efficient that getting the required info from the user
> space.
>
> >
> >> What do you think?
> >> My implementation was module based because I tried to avoid changes
> >> to DAMON core for the RFC.
> >
> > If there is a good reason to implement that not in the user space but the
> > kernel space, as I mentioned above, it seems the module is the right place to
> > me.
I agree it would be much more efficient to do that in the kernel space. But,
given existence of 'top' like user space programs that also does similar works
and heavily used, I'm not directly feeling how important the efficiency is in
the real life.
Meanwhile, doing it in the user space (DAMON user-space tool or your own one)
would be simpler and more flexible. For example, you could simply use 'ps
--sort=%cpu', and make the sorting algorithm flexible (e.g., sorting by RSS or
using different sorting algorithms) without changing kernel.
So there are pros and cons, to my humble view. Those may depend on the given
use case, and I want to focus on your planned or expected use case. Could you
please clarify your planned or expected use case, and how important and trivial
the pros and cons of keeping the logic in kernel or user space would be on the
scenarios?
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
` (4 preceding siblings ...)
2026-02-03 1:10 ` [RFC PATCH v1 0/4] mm/damon: Support hot application detections SeongJae Park
@ 2026-02-11 6:59 ` SeongJae Park
2026-02-11 11:29 ` Gutierrez Asier
5 siblings, 1 reply; 22+ messages in thread
From: SeongJae Park @ 2026-02-11 6:59 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>
> Overview
> ----------
>
> This patch set introduces a new dynamic mechanism for detecting hot applications
> and hot regions in those applications.
>
> Motivation
> -----------
>
> Currently DAMON requires the system administrator to provide information about
> which application needs to be monitored and all the parameters. Ideally this
> should be done automatically, with minimal intervention from the system
> administrator.
>
>
> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
> fragmentation and memory waste. For this reason, most application guides and
> system administrators suggest to disable THP.
>
> We would like to detect: 1. which applications are hot in the system and 2.
> which memory regions are hot in order to collapse those regions.
>
>
> Solution
> -----------
>
> ┌────────────┐ ┌────────────┐
> │Damon_module│ │Task_monitor│
> └──────┬─────┘ └──────┬─────┘
> │ start │
> │───────────────────────>│
> │ │
> │ │────┐
> │ │ │ calculate task load
> │ │<───┘
> │ │
> │ │────┐
> │ │ │ sort tasks
> │ │<───┘
> │ │
> │ │────┐
> │ │ │ start kdamond for top 3 tasks
> │ │<───┘
> ┌──────┴─────┐ ┌──────┴─────┐
> │Damon_module│ │Task_monitor│
> └────────────┘ └────────────┘
>
>
> We calculate the task load base on the sum of all the utime for all the threads
> in a given task. Once we get total utime, we use the exponential load average
> provided by calc_load. The tasks that become cold, the kdamond will be stopped
> for them.
>
> In each kdamond, we start with a high min_access value. Our goal is to find the
> "maximum" min_access value at which point the DAMON action is applied. In each
> cycle, if no action is applied, we lower the min_access.
>
> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
> collapse synchronously and avoid polluting khugepaged and other parts of the MM
> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
> which needs the correct vm_flags_t set.
>
> Benchmark
> -----------
>
> Asier Gutierrez (4):
> mm/damon: Generic context creation for modules
> mm/damon: Support for synchrounous huge pages collapse
> mm/damon: New module with hot application detection
> documentation/mm/damon: Documentation for the dynamic_hugepages
> module
>
> .../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++
> include/linux/damon.h | 1 +
> mm/damon/Kconfig | 7 +
> mm/damon/Makefile | 1 +
> mm/damon/dynamic_hugepages.c (new) | 579 ++++++++++++++++++
> mm/damon/lru_sort.c | 6 +-
> mm/damon/modules-common.c | 7 +-
> mm/damon/modules-common.h | 5 +-
> mm/damon/reclaim.c | 5 +-
> mm/damon/vaddr.c | 3 +
> 10 files changed, 778 insertions(+), 9 deletions(-)
> create mode 100644 Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
> create mode 100644 mm/damon/dynamic_hugepages.c
By the way, I proposed [1] an LSF/MM/BPF session for access-aware THP today. I
also mentioned this patch series on the proposal as one of potential discussion
topics, and Cc-ed Asier.
I just wanted to make sure that the proposal is never a sort of implicit
request to hold the progress of this patch series. Please continue discussions
and revisioning of this patch series regardless of the proposed LSF/MM/BPF
session.
[1] https://lore.kernel.org/20260211050729.69719-1-sj@kernel.org
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-11 6:59 ` SeongJae Park
@ 2026-02-11 11:29 ` Gutierrez Asier
2026-02-11 15:09 ` SeongJae Park
0 siblings, 1 reply; 22+ messages in thread
From: Gutierrez Asier @ 2026-02-11 11:29 UTC (permalink / raw)
To: SeongJae Park
Cc: artem.kuzin, stepanov.anatoly, wangkefeng.wang, yanquanmin1,
zuoze1, damon, akpm, linux-mm, linux-kernel
Hi SeongJae,
On 2/11/2026 9:59 AM, SeongJae Park wrote:
> On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
>
>> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
>>
>> Overview
>> ----------
>>
>> This patch set introduces a new dynamic mechanism for detecting hot applications
>> and hot regions in those applications.
>>
>> Motivation
>> -----------
>>
>> Currently DAMON requires the system administrator to provide information about
>> which application needs to be monitored and all the parameters. Ideally this
>> should be done automatically, with minimal intervention from the system
>> administrator.
>>
>>
>> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
>> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
>> fragmentation and memory waste. For this reason, most application guides and
>> system administrators suggest to disable THP.
>>
>> We would like to detect: 1. which applications are hot in the system and 2.
>> which memory regions are hot in order to collapse those regions.
>>
>>
>> Solution
>> -----------
>>
>> ┌────────────┐ ┌────────────┐
>> │Damon_module│ │Task_monitor│
>> └──────┬─────┘ └──────┬─────┘
>> │ start │
>> │───────────────────────>│
>> │ │
>> │ │────┐
>> │ │ │ calculate task load
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ sort tasks
>> │ │<───┘
>> │ │
>> │ │────┐
>> │ │ │ start kdamond for top 3 tasks
>> │ │<───┘
>> ┌──────┴─────┐ ┌──────┴─────┐
>> │Damon_module│ │Task_monitor│
>> └────────────┘ └────────────┘
>>
>>
>> We calculate the task load base on the sum of all the utime for all the threads
>> in a given task. Once we get total utime, we use the exponential load average
>> provided by calc_load. The tasks that become cold, the kdamond will be stopped
>> for them.
>>
>> In each kdamond, we start with a high min_access value. Our goal is to find the
>> "maximum" min_access value at which point the DAMON action is applied. In each
>> cycle, if no action is applied, we lower the min_access.
>>
>> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
>> collapse synchronously and avoid polluting khugepaged and other parts of the MM
>> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
>> which needs the correct vm_flags_t set.
>>
>> Benchmark
>> -----------
>>
>> Asier Gutierrez (4):
>> mm/damon: Generic context creation for modules
>> mm/damon: Support for synchrounous huge pages collapse
>> mm/damon: New module with hot application detection
>> documentation/mm/damon: Documentation for the dynamic_hugepages
>> module
>>
>> .../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++
>> include/linux/damon.h | 1 +
>> mm/damon/Kconfig | 7 +
>> mm/damon/Makefile | 1 +
>> mm/damon/dynamic_hugepages.c (new) | 579 ++++++++++++++++++
>> mm/damon/lru_sort.c | 6 +-
>> mm/damon/modules-common.c | 7 +-
>> mm/damon/modules-common.h | 5 +-
>> mm/damon/reclaim.c | 5 +-
>> mm/damon/vaddr.c | 3 +
>> 10 files changed, 778 insertions(+), 9 deletions(-)
>> create mode 100644 Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
>> create mode 100644 mm/damon/dynamic_hugepages.c
>
> By the way, I proposed [1] an LSF/MM/BPF session for access-aware THP today. I
> also mentioned this patch series on the proposal as one of potential discussion
> topics, and Cc-ed Asier.
>
> I just wanted to make sure that the proposal is never a sort of implicit
> request to hold the progress of this patch series. Please continue discussions
> and revisioning of this patch series regardless of the proposed LSF/MM/BPF
> session.
>
> [1] https://lore.kernel.org/20260211050729.69719-1-sj@kernel.org
>
>
> Thanks,
> SJ
>
> [...]
>
Yes, I keep working on this, I haven't given up.
I was thinking about your comments and about the overall idea. When you
mentioned goals and autotuning, were you referring to DAMOS_QUOTA_USER_INPUT?
The idea was to adjust the min_nr_accesses for region and I haven't found a way
to adjust the damos_access_pattern using goals and quotas. If there is a way to
do it, it may be a good idea to reuse already existing components.
Also, I thought about moving part of the logic to user space. What do you think
if we leave the hot application detection mechanism in the user space and we
keep the THP part and autotuning in the kernel? Maybe this way we can move
forward easier and eventually merge it in the mainstream.
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC PATCH v1 0/4] mm/damon: Support hot application detections
2026-02-11 11:29 ` Gutierrez Asier
@ 2026-02-11 15:09 ` SeongJae Park
0 siblings, 0 replies; 22+ messages in thread
From: SeongJae Park @ 2026-02-11 15:09 UTC (permalink / raw)
To: Gutierrez Asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, linux-mm, linux-kernel
On Wed, 11 Feb 2026 14:29:41 +0300 Gutierrez Asier <gutierrez.asier@huawei-partners.com> wrote:
> Hi SeongJae,
>
> On 2/11/2026 9:59 AM, SeongJae Park wrote:
> > On Mon, 2 Feb 2026 14:56:45 +0000 <gutierrez.asier@huawei-partners.com> wrote:
> >
> >> From: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
> >>
> >> Overview
> >> ----------
> >>
> >> This patch set introduces a new dynamic mechanism for detecting hot applications
> >> and hot regions in those applications.
> >>
> >> Motivation
> >> -----------
> >>
> >> Currently DAMON requires the system administrator to provide information about
> >> which application needs to be monitored and all the parameters. Ideally this
> >> should be done automatically, with minimal intervention from the system
> >> administrator.
> >>
> >>
> >> Since TLB is a bottleneck for many systems, a way to optimize TLB misses (or
> >> hits) is to use huge pages. Unfortunately, using "always" in THP leads to memory
> >> fragmentation and memory waste. For this reason, most application guides and
> >> system administrators suggest to disable THP.
> >>
> >> We would like to detect: 1. which applications are hot in the system and 2.
> >> which memory regions are hot in order to collapse those regions.
> >>
> >>
> >> Solution
> >> -----------
> >>
> >> ┌────────────┐ ┌────────────┐
> >> │Damon_module│ │Task_monitor│
> >> └──────┬─────┘ └──────┬─────┘
> >> │ start │
> >> │───────────────────────>│
> >> │ │
> >> │ │────┐
> >> │ │ │ calculate task load
> >> │ │<───┘
> >> │ │
> >> │ │────┐
> >> │ │ │ sort tasks
> >> │ │<───┘
> >> │ │
> >> │ │────┐
> >> │ │ │ start kdamond for top 3 tasks
> >> │ │<───┘
> >> ┌──────┴─────┐ ┌──────┴─────┐
> >> │Damon_module│ │Task_monitor│
> >> └────────────┘ └────────────┘
> >>
> >>
> >> We calculate the task load base on the sum of all the utime for all the threads
> >> in a given task. Once we get total utime, we use the exponential load average
> >> provided by calc_load. The tasks that become cold, the kdamond will be stopped
> >> for them.
> >>
> >> In each kdamond, we start with a high min_access value. Our goal is to find the
> >> "maximum" min_access value at which point the DAMON action is applied. In each
> >> cycle, if no action is applied, we lower the min_access.
> >>
> >> Regarding the action, we introduce a new action: DAMOS_COLLAPSE. This allows us
> >> collapse synchronously and avoid polluting khugepaged and other parts of the MM
> >> subsystem with DAMON stuff. DAMOS_HUGEPAGE eventually calls hugepage_madvise,
> >> which needs the correct vm_flags_t set.
> >>
> >> Benchmark
> >> -----------
> >>
> >> Asier Gutierrez (4):
> >> mm/damon: Generic context creation for modules
> >> mm/damon: Support for synchrounous huge pages collapse
> >> mm/damon: New module with hot application detection
> >> documentation/mm/damon: Documentation for the dynamic_hugepages
> >> module
> >>
> >> .../mm/damon/dynamic_hugepages.rst (new) | 173 ++++++
> >> include/linux/damon.h | 1 +
> >> mm/damon/Kconfig | 7 +
> >> mm/damon/Makefile | 1 +
> >> mm/damon/dynamic_hugepages.c (new) | 579 ++++++++++++++++++
> >> mm/damon/lru_sort.c | 6 +-
> >> mm/damon/modules-common.c | 7 +-
> >> mm/damon/modules-common.h | 5 +-
> >> mm/damon/reclaim.c | 5 +-
> >> mm/damon/vaddr.c | 3 +
> >> 10 files changed, 778 insertions(+), 9 deletions(-)
> >> create mode 100644 Documentation/admin-guide/mm/damon/dynamic_hugepages.rst
> >> create mode 100644 mm/damon/dynamic_hugepages.c
> >
> > By the way, I proposed [1] an LSF/MM/BPF session for access-aware THP today. I
> > also mentioned this patch series on the proposal as one of potential discussion
> > topics, and Cc-ed Asier.
> >
> > I just wanted to make sure that the proposal is never a sort of implicit
> > request to hold the progress of this patch series. Please continue discussions
> > and revisioning of this patch series regardless of the proposed LSF/MM/BPF
> > session.
> >
> > [1] https://lore.kernel.org/20260211050729.69719-1-sj@kernel.org
> >
> >
> > Thanks,
> > SJ
> >
> > [...]
> >
>
> Yes, I keep working on this, I haven't given up.
Thank you Asier :)
>
> I was thinking about your comments and about the overall idea. When you
> mentioned goals and autotuning, were you referring to DAMOS_QUOTA_USER_INPUT?
> The idea was to adjust the min_nr_accesses for region and I haven't found a way
> to adjust the damos_access_pattern using goals and quotas. If there is a way to
> do it, it may be a good idea to reuse already existing components.
I was not asking with DAMOS_QUOTA_USER_INPUT or a specific usage of DAMOS quota
goal feature for this use case in my mind. Rather than that, I was asking
because I am also finding if there is a good way to utilize the feature for
THP. That is, I wanted to know if you also tried that but resulted in using
a different way, because you found the feature cannot be used, and if so, what
options you tried.
One brainstorming idea I have, which I also want to further discuss on
LSF/MM/BPF is, making a new DAMOS quota goal metric. For example, ratio of thp
to normal page. Then, we can setup a DAMOS scheme of THP collapse action, with
quota goal of the metric, targeting, say, 50%. Then DAMOS will automatically
adjust the scheme's aggressiveeness so that the target memory region to have
THP for 50% of it, in eventual. Is 50% reasonable? I feel that's good enough
for at least being default value as long as users can tweak. But I have no
concrete theory, and didn't test. Hence I'm saying I found no good but only
brain storming idea yet. Yet another possible quota goal metric would be THP
hit rate, or THP collapse-causing kernel time increase.
>
> Also, I thought about moving part of the logic to user space. What do you think
> if we leave the hot application detection mechanism in the user space and we
> keep the THP part and autotuning in the kernel? Maybe this way we can move
> forward easier and eventually merge it in the mainstream.
I agree that could be easier way. Particularly, adding a new DAMOS action for
THP collapsing should be pretty easy in my opinion. The expected usage and
benefit is clear to me, and the required change is quite simple (easy to
maintain). If you have any good test results with it, I find no reason to
object it.
For auto-tuning, if you are saying the current min_nr_accesses adjustment in
the module, I'm not very sure if I'm understanding how it will look like. A
few questions off the top of my head about it are: Will it be another core
feature? Or, will it be the module's feature? Will it be optional? Why it
cannot be a new metric of DAMOS quota auto-tuning? What is the performance
results? And more. So I'd like to take another round of detailed review.
Nevertheless, even with the current shape, if your planned usage is clear,
tested benefit is significant, and you have valid reason to upstream this as is
for your selfish use case, I wouldn't say "no" at upstreaming it. I may ask
some clarifications and cleanups, of course, though.
So, if you have concrete usage plan, quite good test results, and reason to
upstream it asap, please feel free to push it as is. Upstreaming easy parts
first one by one would also be good strategy. For example, THP collapsing
DAMOS action first, then auto-tuning (it may results in the current way, a new
DAMOS quota goal metric, or somewhat much better than what we discuss now), and
finally hot applications detection and more.
Whether to upstream it as is at once or doing it in smaller pieces is solely up
to you. I feel like I sligtly prefer the latter one, but never a strong
opinion. Whatever you choose, I will be happy to help :)
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-02-11 15:09 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-02 14:56 [RFC PATCH v1 0/4] mm/damon: Support hot application detections gutierrez.asier
2026-02-02 14:56 ` [RFC PATCH v1 1/4] mm/damon: Generic context creation for modules gutierrez.asier
2026-02-03 1:16 ` SeongJae Park
2026-02-03 13:04 ` Gutierrez Asier
2026-02-02 14:56 ` [RFC PATCH v1 2/4] mm/damon: Support for synchrounous huge pages collapse gutierrez.asier
2026-02-03 1:23 ` SeongJae Park
2026-02-03 14:04 ` Gutierrez Asier
2026-02-02 14:56 ` [RFC PATCH v1 3/4] mm/damon: New module with hot application detection gutierrez.asier
2026-02-03 5:04 ` SeongJae Park
2026-02-03 14:21 ` Gutierrez Asier
2026-02-02 14:56 ` [RFC PATCH v1 4/4] documentation/mm/damon: Documentation for the dynamic_hugepages module gutierrez.asier
2026-02-03 5:34 ` SeongJae Park
2026-02-03 1:10 ` [RFC PATCH v1 0/4] mm/damon: Support hot application detections SeongJae Park
2026-02-03 13:03 ` Gutierrez Asier
2026-02-04 7:31 ` SeongJae Park
2026-02-03 14:25 ` Gutierrez Asier
2026-02-04 7:17 ` SeongJae Park
2026-02-04 13:07 ` Gutierrez Asier
2026-02-04 15:43 ` SeongJae Park
2026-02-11 6:59 ` SeongJae Park
2026-02-11 11:29 ` Gutierrez Asier
2026-02-11 15:09 ` SeongJae Park
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox