From nobody Thu Apr 2 09:40:43 2026 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E0BE3AD52A for ; Tue, 10 Mar 2026 16:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; cv=none; b=tR+1SKMBNLrfdFCV6jdQvZR+Vqs06dbl1X6ankPnf+ko5nIpgQnBrC2jO5p+IflB6OvQhLsN17XhWbzkTwLGOT4p0aw4F2XIgHrjbM4+jY7rVBr9eMbJqEOjH/pDufzdNTEDzj06Xs7xM+Zsnfxlsx96WUvJVn4ENZPKAN7Uc3w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; c=relaxed/simple; bh=IXH2O5agTgh9CJ1mRB/AuCT8El7x5dwINlrV7qaZ+5c=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Xm9VfXRLgx+FbT6PEFOtDV5dLBqwf6vRCl3Fe2mwSNQg+k+ykJrTg10rcAIy38usNVmr1qz1dbC1l28W5zK/0qL/iAuIPJ4ucQ+kCQ4R3EglqXViXKSLkHlV94ln0g7UmlJ1e+SQvmadFhClYXo76Z36xxpjFbgt5zUjZJtx590= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.18.224.83]) by frasgout.his.huawei.com (SkyGuard) with ESMTPS id 4fVfNd1dkxzJ467N; Wed, 11 Mar 2026 00:24:49 +0800 (CST) Received: from mscpeml500003.china.huawei.com (unknown [7.188.49.51]) by mail.maildlp.com (Postfix) with ESMTPS id 0F59840086; Wed, 11 Mar 2026 00:25:34 +0800 (CST) Received: from mscphis01197.huawei.com (10.123.65.218) by mscpeml500003.china.huawei.com (7.188.49.51) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 10 Mar 2026 19:25:33 +0300 From: To: , , , , , , , , , , Subject: [RFC PATCH v2 1/4] mm/damon: Generic context creation for modules Date: Tue, 10 Mar 2026 16:24:17 +0000 Message-ID: <20260310162420.4180562-2-gutierrez.asier@huawei-partners.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> References: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: mscpeml500004.china.huawei.com (7.188.26.250) To mscpeml500003.china.huawei.com (7.188.49.51) Content-Type: text/plain; charset="utf-8" From: Asier Gutierrez 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 Co-developed-by: Anatoly Stepanov --- mm/damon/lru_sort.c | 5 +++-- mm/damon/modules-common.c | 6 +++--- mm/damon/modules-common.h | 4 ++-- mm/damon/reclaim.c | 5 +++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c index 7bc5c0b2aea3..143ee0b21da6 100644 --- a/mm/damon/lru_sort.c +++ b/mm/damon/lru_sort.c @@ -287,7 +287,8 @@ static int damon_lru_sort_apply_parameters(void) unsigned int hot_thres, cold_thres; int err; =20 - err =3D damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target); + err =3D damon_modules_new_ctx_target(¶m_ctx, ¶m_target, + DAMON_OPS_PADDR); if (err) return err; =20 @@ -479,7 +480,7 @@ static int __init damon_lru_sort_init(void) err =3D -ENOMEM; goto out; } - err =3D damon_modules_new_paddr_ctx_target(&ctx, &target); + err =3D damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_PADDR); if (err) goto out; =20 diff --git a/mm/damon/modules-common.c b/mm/damon/modules-common.c index 86d58f8c4f63..ae50b2fa3a86 100644 --- a/mm/damon/modules-common.c +++ b/mm/damon/modules-common.c @@ -14,8 +14,8 @@ * @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 +24,7 @@ int damon_modules_new_paddr_ctx_target(struct damon_ctx *= *ctxp, if (!ctx) return -ENOMEM; =20 - 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..379b49c6a617 100644 --- a/mm/damon/modules-common.h +++ b/mm/damon/modules-common.h @@ -45,5 +45,5 @@ module_param_named(nr_##qt_exceed_name, stat.qt_exceeds, ulong, \ 0400); =20 -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 43d76f5bed44..24786a58683a 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; =20 - err =3D damon_modules_new_paddr_ctx_target(¶m_ctx, ¶m_target); + err =3D damon_modules_new_ctx_target(¶m_ctx, ¶m_target, + DAMON_OPS_PADDR); if (err) return err; =20 @@ -381,7 +382,7 @@ static int __init damon_reclaim_init(void) err =3D -ENOMEM; goto out; } - err =3D damon_modules_new_paddr_ctx_target(&ctx, &target); + err =3D damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_PADDR); if (err) goto out; =20 --=20 2.43.0 From nobody Thu Apr 2 09:40:43 2026 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E4573C062B for ; Tue, 10 Mar 2026 16:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; cv=none; b=T6W18XO1kQm9nd7k5kcnagx8rzkzU6dRF613o9YzFtBkEeSw5JWJbzsAlAZzJbe0LFknVIYNCz5z70ezSiqoCepHHoF/vLScq5MWB5kTjsbcICxF5qUM85ILm5LoRE3mSMfYnJ7MXiSCCoIc68GPqJVdrL0cVM2j+WsTBYgTDnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; c=relaxed/simple; bh=VI2PM21MrOU5iz4b76NvZggsYEB0wlt6xKlix1OQhQc=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZLPS0pTizt1ajVHxLJwG/F7whnCLP9z+2GRNolOIfnM64Mhr5d3PxERDTFff24PVqi+fgsOJRNasPxMujKm58NINGu0QMcB4wyhRLxDiNhSK4RgnsWAXCEXU+EkvrMZZq4WpNSmQ7AgIHBELfaV0IEoeYiPArtVOlA2osIV56ys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.18.224.83]) by frasgout.his.huawei.com (SkyGuard) with ESMTPS id 4fVfNd2Dg6zJ469b; Wed, 11 Mar 2026 00:24:49 +0800 (CST) Received: from mscpeml500003.china.huawei.com (unknown [7.188.49.51]) by mail.maildlp.com (Postfix) with ESMTPS id 23EAB40086; Wed, 11 Mar 2026 00:25:34 +0800 (CST) Received: from mscphis01197.huawei.com (10.123.65.218) by mscpeml500003.china.huawei.com (7.188.49.51) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 10 Mar 2026 19:25:33 +0300 From: To: , , , , , , , , , , Subject: [RFC PATCH v2 2/4] mm/damon: Support for synchrounous huge pages collapse Date: Tue, 10 Mar 2026 16:24:18 +0000 Message-ID: <20260310162420.4180562-3-gutierrez.asier@huawei-partners.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> References: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: mscpeml500004.china.huawei.com (7.188.26.250) To mscpeml500003.china.huawei.com (7.188.49.51) Content-Type: text/plain; charset="utf-8" From: Asier Gutierrez Signed-off-by: Asier Gutierrez Co-developed-by: Anatoly Stepanov --- include/linux/damon.h | 1 + mm/damon/vaddr.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/linux/damon.h b/include/linux/damon.h index a4fea23da857..a9cf17b9e8fa 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/vaddr.c b/mm/damon/vaddr.c index 729b7ffd3565..36791a9a1094 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -969,6 +969,9 @@ static unsigned long damon_va_apply_scheme(struct damon= _ctx *ctx, case DAMOS_NOHUGEPAGE: madv_action =3D MADV_NOHUGEPAGE; break; + case DAMOS_COLLAPSE: + madv_action =3D MADV_COLLAPSE; + break; case DAMOS_MIGRATE_HOT: case DAMOS_MIGRATE_COLD: return damos_va_migrate(t, r, scheme, sz_filter_passed); --=20 2.43.0 From nobody Thu Apr 2 09:40:43 2026 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E00034EEF9 for ; Tue, 10 Mar 2026 16:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; cv=none; b=Gca9Q65NfWjuLzwxSOsRpQa3W2LqCA4DtHgUMYIzUK2+y8b0Sy3eu62VYjBPs1jAKQsvkOh0i4fZgaIaKFTLazHDWjj7Lu2uiebJ0hLS7J2fgq1+pXwKqFJkaB0aTr5ZZzPIDPlfhw+WlV4ac29G7AVJFZeQ+3+kRacPM4TJm44= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; c=relaxed/simple; bh=TaBSgBju+exH/fvrUpx4M55Ffp8kmGJjedL2LI6btL8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Slk2q6Dl8Yx2VnzQaHwvZaJu6msh+DpgQh1JnAjxdK1DrTfHntt/PPcWNY+dLeJ7tQbq+ha8lJ4sqtMLHoq8UJKxZwi0lqf1QssBzyYUICefnu7tmIURgVSL8GOoMva3myfpyCdI0Tbh1KbFvkPSL1PswiG+O5HlORYe21Ykk/Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.18.224.83]) by frasgout.his.huawei.com (SkyGuard) with ESMTPS id 4fVfPN1VnpzHnGjq; Wed, 11 Mar 2026 00:25:28 +0800 (CST) Received: from mscpeml500003.china.huawei.com (unknown [7.188.49.51]) by mail.maildlp.com (Postfix) with ESMTPS id 385B940086; Wed, 11 Mar 2026 00:25:34 +0800 (CST) Received: from mscphis01197.huawei.com (10.123.65.218) by mscpeml500003.china.huawei.com (7.188.49.51) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 10 Mar 2026 19:25:33 +0300 From: To: , , , , , , , , , , Subject: [RFC PATCH v2 3/4] mm/damon: New module with hot application detection Date: Tue, 10 Mar 2026 16:24:19 +0000 Message-ID: <20260310162420.4180562-4-gutierrez.asier@huawei-partners.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> References: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: mscpeml500004.china.huawei.com (7.188.26.250) To mscpeml500003.china.huawei.com (7.188.49.51) Content-Type: text/plain; charset="utf-8" From: Asier Gutierrez 1. It first launches a new kthread called damon_dynamic. This thread will behave as a supervisor, launching new kdamond threads for all the processes we want to montiored. 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. The processes are supplied by the monitored_pids parameter. When the module is enabled, it will go through all the monitored_pids, start the supervisor and a new kdamond thread for each of the tasks. This tasks can be modified and applied using the commit_input parameters. In that case, we will stop any kdamond thread for tasks that are not going to be monitored anymore, and start a new kdamond thread for each new task to be monitored. For tasks that were monitored before and are still monitored after commiting a new monitored_pids list, kdamond threads are left intact. 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 Co-developed-by: Anatoly Stepanov --- mm/damon/Kconfig | 7 + mm/damon/Makefile | 1 + mm/damon/hugepage.c (new) | 441 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+) 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. =20 +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..ac3afbc81cc7 100644 --- a/mm/damon/Makefile +++ b/mm/damon/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_DAMON_SYSFS) +=3D sysfs-common.o sysfs-schemes= .o sysfs.o obj-$(CONFIG_DAMON_RECLAIM) +=3D modules-common.o reclaim.o obj-$(CONFIG_DAMON_LRU_SORT) +=3D modules-common.o lru_sort.o obj-$(CONFIG_DAMON_STAT) +=3D modules-common.o stat.o +obj-$(CONFIG_DAMON_HOT_HUGEPAGE) +=3D modules-common.o hugepage.o diff --git a/mm/damon/hugepage.c b/mm/damon/hugepage.c new file mode 100644 index 000000000000..ccd31c48d391 --- /dev/null +++ b/mm/damon/hugepage.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 HUAWEI, Inc. + * https://www.huawei.com + * + * Author: Asier Gutierrez + */ + +#define pr_fmt(fmt) "damon-hugepage: " fmt + +#include +#include +#include + +#include "modules-common.h" + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "damon_hugepage." + +#define MAX_MONITORED_PIDS 100 +#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_HUGEPAGE. + * + * You can enable DAMON_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 t= he + * watermarks-based activation condition. Refer to below descriptions for= the + * watermarks parameter for this. + */ +static bool enabled __read_mostly; + +/* + * Make DAMON_HUGEPAGE reads the input parameters again, except ``enabled`= `. + * + * Input parameters that updated while DAMON_HUGEPAGE is running are not a= pplied + * by default. Once this parameter is set as ``Y``, DAMON_HUGEPAGE reads = values + * of parametrs except ``enabled`` again. Once the re-reading is done, th= is + * parameter is set as ``N``. If invalid parameters are found while the + * re-reading, DAMON_HUGEPAGE will be disabled. + */ +static bool commit_inputs __read_mostly; +module_param(commit_inputs, bool, 0600); + +/* + * DAMON_HUGEPAGE monitoring period in microseconds. + * 5000000 =3D 5s + */ +static unsigned long monitor_period __read_mostly =3D 5000000; +module_param(monitor_period, ulong, 0600); + +static long monitored_pids[MAX_MONITORED_PIDS]; +static int num_monitored_pids; +module_param_array(monitored_pids, long, &num_monitored_pids, 0600); + +static struct damos_quota damon_hugepage_quota =3D { + /* use up to 10 ms time, reclaim up to 128 MiB per 1 sec by default */ + .ms =3D 10, + .sz =3D 0, + .reset_interval =3D 1000, + /* Within the quota, page out older regions first. */ + .weight_sz =3D 0, + .weight_nr_accesses =3D 0, + .weight_age =3D 1 +}; +DEFINE_DAMON_MODULES_DAMOS_TIME_QUOTA(damon_hugepage_quota); + +static struct damos_watermarks damon_hugepage_wmarks =3D { + .metric =3D DAMOS_WMARK_FREE_MEM_RATE, + .interval =3D 5000000, /* 5 seconds */ + .high =3D 900, /* 90 percent */ + .mid =3D 800, /* 80 percent */ + .low =3D 50, /* 5 percent */ +}; +DEFINE_DAMON_MODULES_WMARKS_PARAMS(damon_hugepage_wmarks); + +static struct damon_attrs damon_hugepage_mon_attrs =3D { + .sample_interval =3D 5000, /* 5 ms */ + .aggr_interval =3D 100000, /* 100 ms */ + .ops_update_interval =3D 0, + .min_nr_regions =3D 10, + .max_nr_regions =3D 1000, +}; +DEFINE_DAMON_MODULES_MON_ATTRS_PARAMS(damon_hugepage_mon_attrs); + +struct hugepage_task { + struct damon_ctx *ctx; + int pid; + struct damon_target *target; + struct damon_call_control call_control; + struct list_head list; +}; + +static struct damos *damon_hugepage_new_scheme(int min_access, + enum damos_action action) +{ + struct damos_access_pattern pattern =3D { + /* Find regions having PAGE_SIZE or larger size */ + .min_sz_region =3D PMD_SIZE, + .max_sz_region =3D ULONG_MAX, + /* and not accessed at all */ + .min_nr_accesses =3D min_access, + .max_nr_accesses =3D 100, + /* for min_age or more micro-seconds */ + .min_age_region =3D 0, + .max_age_region =3D UINT_MAX, + }; + + return damon_new_scheme( + &pattern, + /* synchrounous partial collapse as soon as found */ + action, 0, + /* under the quota. */ + &damon_hugepage_quota, + /* (De)activate this according to the watermarks. */ + &damon_hugepage_wmarks, NUMA_NO_NODE); +} + +static int damon_hugepage_apply_parameters( + struct hugepage_task *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; + int err; + struct pid *spid; + + err =3D damon_modules_new_ctx_target(¶m_ctx, ¶m_target, + DAMON_OPS_VADDR); + if (err) + return err; + + spid =3D find_get_pid(monitored_task->pid); + if (!spid) + return err; + + param_target->pid =3D spid; + + err =3D damon_set_attrs(param_ctx, &damon_hugepage_mon_attrs); + if (err) + goto out; + + err =3D -ENOMEM; + scheme =3D damon_hugepage_new_scheme(min_access, action); + if (!scheme) + goto out; + + damon_set_schemes(param_ctx, &scheme, 1); + + filter =3D damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false); + if (!filter) + goto out; + damos_add_filter(scheme, filter); + + err =3D damon_commit_ctx(monitored_task->ctx, param_ctx); +out: + damon_destroy_ctx(param_ctx); + return err; +} + +static int damon_hugepage_damon_call_fn(void *arg) +{ + struct hugepage_task *monitored_task =3D arg; + struct damon_ctx *ctx =3D monitored_task->ctx; + struct damos *scheme; + int err =3D 0; + int min_access; + struct damos_stat stat; + + damon_for_each_scheme(scheme, ctx) + stat =3D scheme->stat; + scheme =3D 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 =3D scheme->pattern.min_nr_accesses; + + if (min_access > HIGH_ACC_THRESHOLD) { + min_access =3D min_access - 10; + err =3D damon_hugepage_apply_parameters( + monitored_task, min_access, DAMOS_COLLAPSE); + } else if (min_access > MID_ACC_THRESHOLD) { + min_access =3D min_access - 5; + err =3D damon_hugepage_apply_parameters( + monitored_task, min_access, DAMOS_COLLAPSE); + } else if (min_access > LOW_ACC_THRESHOLD) { + min_access =3D min_access - 1; + err =3D damon_hugepage_apply_parameters( + monitored_task, min_access, DAMOS_COLLAPSE); + } + return err; +} + +static int damon_hugepage_init_task(struct hugepage_task *monitored_task) +{ + int err =3D 0; + struct damon_ctx *ctx =3D monitored_task->ctx; + struct damon_target *target =3D monitored_task->target; + struct pid *spid; + + if (!ctx || !target) + damon_modules_new_ctx_target(&ctx, &target, DAMON_OPS_VADDR); + + if (damon_is_running(ctx)) + return 0; + + spid =3D find_get_pid(monitored_task->pid); + if (!spid) + return err; + + target->pid =3D spid; + + monitored_task->call_control.fn =3D damon_hugepage_damon_call_fn; + monitored_task->call_control.repeat =3D true; + monitored_task->call_control.data =3D monitored_task; + + struct damos *scheme =3D damon_hugepage_new_scheme( + HIGHEST_MIN_ACCESS, DAMOS_COLLAPSE); + if (!scheme) + return -ENOMEM; + + damon_set_schemes(ctx, &scheme, 1); + + monitored_task->ctx =3D ctx; + err =3D damon_start(&monitored_task->ctx, 1, false); + if (err) + return err; + + return damon_call(monitored_task->ctx, &monitored_task->call_control); +} + +static int add_monitored_task(int pid, struct list_head *task_monitor) +{ + struct hugepage_task *new_hugepage_task; + int err; + + new_hugepage_task =3D kzalloc_obj(*new_hugepage_task); + if (!new_hugepage_task) + return -ENOMEM; + + new_hugepage_task->pid =3D pid; + INIT_LIST_HEAD(&new_hugepage_task->list); + err =3D damon_hugepage_init_task(new_hugepage_task); + if (err) + return err; + list_add(&new_hugepage_task->list, task_monitor); + return 0; +} + +static int damon_hugepage_handle_commit_inputs( + struct list_head *monitored_tasks) +{ + int i =3D 0; + int err =3D 0; + bool found; + struct hugepage_task *monitored_task, *tmp; + + if (!commit_inputs) + return 0; + + while (i < MAX_MONITORED_PIDS) { + if (!monitored_pids[i]) + break; + + found =3D false; + + rcu_read_lock(); + if (!find_vpid(monitored_pids[i])) { + rcu_read_unlock(); + continue; + } + + rcu_read_unlock(); + + list_for_each_entry_safe(monitored_task, tmp, monitored_tasks, list) { + if (monitored_task->pid =3D=3D monitored_pids[i]) { + list_move(&monitored_task->list, monitored_tasks); + found =3D true; + break; + } + } + if (!found) { + err =3D add_monitored_task(monitored_pids[i], monitored_tasks); + /* Skip failed tasks */ + if (err) + continue; + } + i++; + } + + i =3D 0; + list_for_each_entry_safe(monitored_task, tmp, monitored_tasks, list) { + i++; + if (i <=3D num_monitored_pids) + continue; + + err =3D damon_stop(&monitored_task->ctx, 1); + damon_destroy_ctx(monitored_task->ctx); + list_del(&monitored_task->list); + kfree(monitored_task); + } + + commit_inputs =3D false; + return err; +} + +static int damon_manager_monitor_thread(void *data) +{ + int err =3D 0; + int i; + struct hugepage_task *entry, *tmp; + + LIST_HEAD(monitored_tasks); + + for (i =3D 0; i < MAX_MONITORED_PIDS; i++) { + if (!monitored_pids[i]) + break; + + rcu_read_lock(); + if (!find_vpid(monitored_pids[i])) { + rcu_read_unlock(); + continue; + } + rcu_read_unlock(); + + add_monitored_task(monitored_pids[i], &monitored_tasks); + } + + + while (!kthread_should_stop()) { + schedule_timeout_idle(usecs_to_jiffies(monitor_period)); + err =3D damon_hugepage_handle_commit_inputs(&monitored_tasks); + if (err) + break; + } + + list_for_each_entry_safe(entry, tmp, &monitored_tasks, list) { + err =3D damon_stop(&entry->ctx, 1); + damon_destroy_ctx(entry->ctx); + } + + for (int i =3D 0; i < MAX_MONITORED_PIDS;) { + monitored_pids[i] =3D 0; + i++; + } + return err; +} + +static int damon_hugepage_start_monitor_thread(void) +{ + num_monitored_pids =3D 0; + monitor_thread =3D 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_hugepage_turn(bool on) +{ + int err =3D 0; + + mutex_lock(&enable_disable_lock); + if (!on) { + if (monitor_thread) { + kthread_stop(monitor_thread); + monitor_thread =3D NULL; + } + goto out; + } + err =3D damon_hugepage_start_monitor_thread(); +out: + mutex_unlock(&enable_disable_lock); + return err; +} + +static int damon_hugepage_enabled_store(const char *val, + const struct kernel_param *kp) +{ + bool is_enabled =3D enabled; + bool enable; + int err; + + err =3D kstrtobool(val, &enable); + if (err) + return err; + + if (is_enabled =3D=3D enable) + return 0; + + err =3D damon_hugepage_turn(enable); + if (err) + return err; + + enabled =3D enable; + return err; +} + +static const struct kernel_param_ops enabled_param_ops =3D { + .set =3D damon_hugepage_enabled_store, + .get =3D 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_hugepage_init(void) +{ + int err; + + /* 'enabled' has set before this function, probably via command line */ + if (enabled) + err =3D damon_hugepage_turn(true); + + if (err && enabled) + enabled =3D false; + return err; +} + +module_init(damon_hugepage_init); --=20 2.43.0 From nobody Thu Apr 2 09:40:43 2026 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E5613C063C for ; Tue, 10 Mar 2026 16:25:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.176.79.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; cv=none; b=SXgs6k+Szu6RkFt5gg3J2avuI+LdOLcdySnnJp0hbu8Ag2i5RxsN0OedgSc3b2JX6ZrvZV4cSLColAkbWyPNox4qnctgh/ViwyVI6o0YGkFMKsEAn7IyT7unwZzAf35dzcKz1h4VNRfHmTsVjqesWOKzF1iZp1rY8E0brXZdv2s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773159939; c=relaxed/simple; bh=HqsAeC9EO8Mv3nmO/29GvCXOg2xFbDpa1HG7aIOnmHs=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=V/JmExvq5hkLQrsncsnDe0kubY/hoQaoIclpvZJRX0/jhGG5UFmleiMcGq8N7CxVnes3uZxmyqFbqEXge7pc6XoUDOJScIoDB5Dak35CrK+d+yh7GbkI0Pu/V7MaWdIB8aJBHJpwLBk9SLsJ4Ltv/VyqqY5ScKpubOc0Fmdlv4A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=185.176.79.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.18.224.150]) by frasgout.his.huawei.com (SkyGuard) with ESMTPS id 4fVfNd5FYPzJ467L; Wed, 11 Mar 2026 00:24:49 +0800 (CST) Received: from mscpeml500003.china.huawei.com (unknown [7.188.49.51]) by mail.maildlp.com (Postfix) with ESMTPS id 8AF044056B; Wed, 11 Mar 2026 00:25:34 +0800 (CST) Received: from mscphis01197.huawei.com (10.123.65.218) by mscpeml500003.china.huawei.com (7.188.49.51) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Tue, 10 Mar 2026 19:25:34 +0300 From: To: , , , , , , , , , , Subject: [RFC PATCH v2 4/4] DAMON_HOT_HUGEPAGE documentation Date: Tue, 10 Mar 2026 16:24:20 +0000 Message-ID: <20260310162420.4180562-5-gutierrez.asier@huawei-partners.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> References: <20260310162420.4180562-1-gutierrez.asier@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: mscpeml500004.china.huawei.com (7.188.26.250) To mscpeml500003.china.huawei.com (7.188.49.51) Content-Type: text/plain; charset="utf-8" From: Asier Gutierrez Documentation for hugepage DAMON module. Signed-off-by: Asier Gutierrez Co-developed-by: Anatoly Stepanov --- .../admin-guide/mm/damon/hugepage.rst (new) | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/Documentation/admin-guide/mm/damon/hugepage.rst b/Documentatio= n/admin-guide/mm/damon/hugepage.rst new file mode 100644 index 000000000000..a7b20a670824 --- /dev/null +++ b/Documentation/admin-guide/mm/damon/hugepage.rst @@ -0,0 +1,186 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +DAMON-based Huge Pages Collapsing +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +DAMON-based dynamic hugepages collapsing (DAMON_HOT_HUGEPAGE) is a kernel = module +that monitors a number of tasks simultaneously. The hot regions are collap= sed +into huge pages. + +Where Hot Region Huge Pages Collapsing is Required? +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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 le= ad to +fragmentation and memory waste, it is usually turned off. + +This module allows to automatically detect hot regions and collapse VMA th= at are +hot. + +How It Works? +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +DAMON_HOT_HUGEPAGE spawns a new kthread which will monitor the application= s in +the system. The monitor thread will calculate the moving average of the su= m 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 initi= ally, +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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D + +To use this feature, you should first ensure your system is running on a k= ernel +that is built with CONFIG_DAMON_HOT_HUGEPAGE=3Dy. + +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.=3D on the kernel boot command li= ne or +write proper values to /sys/module/damon_dynamic_hotpages/parameters/ +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 a= s Y. +Setting it as N disables DAMON_HOT_HUGEPAGE. Note that, although +DAMON_HOT_HUGEPAGE monitors the system and starts damon threads, those thr= eads +could do no real monitoring due to the watermarks-based activation conditi= on. +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 l= imit +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 millise= conds +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_HUGEPA= GE 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 th= is, +DAMON_HOT_HUGEPAGE becomes inactive, so it does nothing but periodically c= hecks +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 a= nd 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 thi= s, +DAMON_HOT_HUGEPAGE becomes inactive, so it does nothing but periodically c= hecks +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 refe= r 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 r= efer +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 defau= lt. + +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. Plea= se +refer to the DAMON documentation (:doc:usage) for more detail. 1000 by def= aults. + +monitored_pids +-------------- + +List of the tasks that are being actively monitored by DAMON threads. + +commit_inputs +------------- + +Make DAMON_HOT_HUGEPAGE reads the input parameters again, except ``enabled= ``. + +Input parameters that updated while DAMON_HOT_HUGEPAGE is running are not +applied by default. Once this parameter is set as ``Y``, DAMON_HOT_HUGEPAGE +reads values of parametrs except ``enabled`` again. Once the re-reading is= done, +this parameter is set as ``N``. If invalid parameters are found while the +re-reading, DAMON_HOT_HUGEPAGE will be disabled. + +Example +=3D=3D=3D=3D=3D=3D=3D +Below runtime example commands make DAMON_HOT_HUGEPAGE to find memory regi= ons in +the 3 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 3811,10123,12111 > monitored_pids + # 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 --=20 2.43.0