* [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
@ 2026-03-20 19:04 Ravi Jonnalagadda
2026-03-20 19:04 ` [RFC PATCH v4 1/1] " Ravi Jonnalagadda
2026-03-21 16:57 ` [RFC PATCH v4 0/1] " SeongJae Park
0 siblings, 2 replies; 8+ messages in thread
From: Ravi Jonnalagadda @ 2026-03-20 19:04 UTC (permalink / raw)
To: sj, damon, linux-mm, linux-kernel, linux-doc
Cc: akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun,
ravis.opensrc
This patch introduces two new DAMON quota goal metrics for controlling
memory distribution in heterogeneous memory systems (e.g., DRAM and CXL
memory tiering) using physical address (PA) mode monitoring.
v3: https://lore.kernel.org/linux-mm/20260223123232.12851-1-ravis.opensrc@gmail.com/
Changes since v3:
=================
- The first two patches from v3 (goal_tuner initialization fix and
esz=0 quota bypass fix) are now in damon/next. This submission
contains only the core metrics patch, rebased on top of those fixes.
- Simplified implementation: removed per-node eligible_bytes array, now
iterates scheme-eligible regions directly for each goal evaluation.
- Handle regions crossing node boundaries: uses damon_get_folio() to
determine actual NUMA node placement of each folio rather than
assuming uniform node placement within a region.
- Pass scheme pointer directly to metric calculation functions, avoiding
container_of() derivation from quota pointer.
- Fixed 80-column wrapping issues.
Background and Motivation
=========================
In heterogeneous memory systems, controlling memory distribution across
NUMA nodes is essential for performance optimization. This patch enables
system-wide page distribution with target-state goals like "maintain 30%
of scheme-eligible memory on CXL" using PA-mode DAMON schemes.
What These Metrics Measure
==========================
node_eligible_mem_bp:
scheme_eligible_bytes_on_node / total_scheme_eligible_bytes * 10000
node_ineligible_mem_bp:
(total - scheme_eligible_bytes_on_node) / total * 10000
The metrics are complementary: eligible_bp + ineligible_bp = 10000 bp.
Two-Scheme Setup for Hot Page Distribution
==========================================
For maintaining 30% of hot memory on CXL (node 1):
PUSH scheme: migrate_hot from node 0 -> node 1
goal: node_ineligible_mem_bp, nid=0, target=3000
"Push hot pages out until 30% of hot memory is NOT on DRAM"
PULL scheme: migrate_hot from node 1 -> node 0
goal: node_eligible_mem_bp, nid=0, target=7000
"Pull hot pages back until 70% of hot memory IS on DRAM"
The complementary goals create a feedback loop that converges to the
target distribution.
Dependencies
============
This patch is based on SJ's damon/next branch which includes the
TEMPORAL goal tuner required for these metrics.
Testing Results
===============
Functionally tested on a two-node heterogeneous memory system with DRAM
(node 0) and CXL memory (node 1). Used PUSH+PULL scheme configuration
with migrate_hot action to maintain a target hot memory ratio between
the two tiers.
With the TEMPORAL goal tuner, the system converges quickly to the target
distribution. The tuner drives esz to maximum when under goal and to
zero once the goal is met, forming a simple on/off feedback loop that
stabilizes at the desired ratio.
With the CONSIST tuner, the scheme still converges but more slowly, as
it migrates and then throttles itself based on quota feedback. The time
to reach the goal varies depending on workload intensity.
Ravi Jonnalagadda (1):
mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal
metrics
include/linux/damon.h | 6 ++
mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++---
mm/damon/sysfs-schemes.c | 12 +++
3 files changed, 164 insertions(+), 12 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-20 19:04 [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics Ravi Jonnalagadda @ 2026-03-20 19:04 ` Ravi Jonnalagadda 2026-03-21 16:54 ` SeongJae Park 2026-03-21 16:57 ` [RFC PATCH v4 0/1] " SeongJae Park 1 sibling, 1 reply; 8+ messages in thread From: Ravi Jonnalagadda @ 2026-03-20 19:04 UTC (permalink / raw) To: sj, damon, linux-mm, linux-kernel, linux-doc Cc: akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun, ravis.opensrc Add new quota goal metrics for memory tiering that track scheme-eligible memory distribution across NUMA nodes: - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on a node These complementary metrics enable push-pull migration schemes that maintain a target memory distribution across different NUMA nodes representing different memory tiers, based on access patterns defined by each scheme. The metrics iterate scheme-eligible regions and use damon_get_folio() to determine NUMA node placement of each folio, calculating the ratio of eligible memory on the specified node versus total eligible memory. Suggested-by: SeongJae Park <sj@kernel.org> Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com> --- include/linux/damon.h | 6 ++ mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++--- mm/damon/sysfs-schemes.c | 12 +++ 3 files changed, 164 insertions(+), 12 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index b1d8fd88a0fc..490918804f85 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -193,6 +193,10 @@ enum damos_action { * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP: MemFree ratio of a node for a cgroup. * @DAMOS_QUOTA_ACTIVE_MEM_BP: Active to total LRU memory ratio. * @DAMOS_QUOTA_INACTIVE_MEM_BP: Inactive to total LRU memory ratio. + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: Scheme-eligible memory ratio of a + * node. + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: Scheme-ineligible memory ratio of a + * node. * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics. * * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported. @@ -206,6 +210,8 @@ enum damos_quota_goal_metric { DAMOS_QUOTA_NODE_MEMCG_FREE_BP, DAMOS_QUOTA_ACTIVE_MEM_BP, DAMOS_QUOTA_INACTIVE_MEM_BP, + DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP, + DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP, NR_DAMOS_QUOTA_GOAL_METRICS, }; diff --git a/mm/damon/core.c b/mm/damon/core.c index b9e12865622c..3e0ac65e34a0 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -17,6 +17,8 @@ #include <linux/string.h> #include <linux/string_choices.h> +#include "ops-common.h" + #define CREATE_TRACE_POINTS #include <trace/events/damon.h> @@ -2552,6 +2554,112 @@ static unsigned long damos_get_node_memcg_used_bp( numerator = i.totalram - used_pages; return mult_frac(numerator, 10000, i.totalram); } + +/* + * damos_calc_eligible_bytes() - Calculate raw eligible bytes per node. + * @c: The DAMON context. + * @s: The scheme. + * @nid: The target NUMA node id. + * @total: Output for total eligible bytes across all nodes. + * + * Iterates through each folio in eligible regions to accurately determine + * which node the memory resides on. Returns eligible bytes on the specified + * node and sets *total to the sum across all nodes. + */ +static unsigned long damos_calc_eligible_bytes(struct damon_ctx *c, + struct damos *s, int nid, unsigned long *total) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long total_eligible = 0; + unsigned long node_eligible = 0; + + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + phys_addr_t addr, end_addr; + + if (!__damos_valid_target(r, s)) + continue; + + /* Convert from core address units to physical bytes */ + addr = r->ar.start * c->addr_unit; + end_addr = r->ar.end * c->addr_unit; + while (addr < end_addr) { + struct folio *folio; + unsigned long folio_sz, counted; + + folio = damon_get_folio(PHYS_PFN(addr)); + if (!folio) { + addr += PAGE_SIZE; + continue; + } + + folio_sz = folio_size(folio); + /* + * Clip to region boundaries to avoid counting + * bytes outside the region when folio spans + * region boundaries. + */ + counted = min(folio_sz, (unsigned long)(end_addr - addr)); + total_eligible += counted; + if (folio_nid(folio) == nid) + node_eligible += counted; + + addr += folio_sz; + folio_put(folio); + } + } + } + + *total = total_eligible; + return node_eligible; +} + +/* + * damos_get_node_eligible_mem_bp() - Get eligible memory ratio for a node. + * @c: The DAMON context. + * @s: The scheme. + * @nid: The target NUMA node id. + * + * Calculates scheme-eligible bytes on the specified node and returns the + * ratio in basis points (0-10000) relative to total eligible bytes across + * all nodes. + */ +static unsigned long damos_get_node_eligible_mem_bp(struct damon_ctx *c, + struct damos *s, int nid) +{ + unsigned long total_eligible = 0; + unsigned long node_eligible = 0; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)) + return 0; + + node_eligible = damos_calc_eligible_bytes(c, s, nid, &total_eligible); + + if (!total_eligible) + return 0; + + return mult_frac(node_eligible, 10000, total_eligible); +} + +static unsigned long damos_get_node_ineligible_mem_bp(struct damon_ctx *c, + struct damos *s, int nid) +{ + unsigned long total_eligible = 0; + unsigned long node_eligible; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)) + return 0; + + node_eligible = damos_calc_eligible_bytes(c, s, nid, &total_eligible); + + /* No eligible memory anywhere - ratio is undefined, return 0 */ + if (!total_eligible) + return 0; + + /* Compute ineligible ratio directly: 10000 - eligible_bp */ + return 10000 - mult_frac(node_eligible, 10000, total_eligible); +} #else static __kernel_ulong_t damos_get_node_mem_bp( struct damos_quota_goal *goal) @@ -2564,6 +2672,18 @@ static unsigned long damos_get_node_memcg_used_bp( { return 0; } + +static unsigned long damos_get_node_eligible_mem_bp(struct damon_ctx *c, + struct damos *s, int nid) +{ + return 0; +} + +static unsigned long damos_get_node_ineligible_mem_bp(struct damon_ctx *c, + struct damos *s, int nid) +{ + return 0; +} #endif /* @@ -2584,7 +2704,8 @@ static unsigned int damos_get_in_active_mem_bp(bool active_ratio) return mult_frac(inactive, 10000, total); } -static void damos_set_quota_goal_current_value(struct damos_quota_goal *goal) +static void damos_set_quota_goal_current_value(struct damon_ctx *c, + struct damos *s, struct damos_quota_goal *goal) { u64 now_psi_total; @@ -2611,19 +2732,28 @@ static void damos_set_quota_goal_current_value(struct damos_quota_goal *goal) goal->current_value = damos_get_in_active_mem_bp( goal->metric == DAMOS_QUOTA_ACTIVE_MEM_BP); break; + case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: + goal->current_value = damos_get_node_eligible_mem_bp(c, s, + goal->nid); + break; + case DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: + goal->current_value = damos_get_node_ineligible_mem_bp(c, s, + goal->nid); + break; default: break; } } /* Return the highest score since it makes schemes least aggressive */ -static unsigned long damos_quota_score(struct damos_quota *quota) +static unsigned long damos_quota_score(struct damon_ctx *c, struct damos *s) { + struct damos_quota *quota = &s->quota; struct damos_quota_goal *goal; unsigned long highest_score = 0; damos_for_each_quota_goal(goal, quota) { - damos_set_quota_goal_current_value(goal); + damos_set_quota_goal_current_value(c, s, goal); highest_score = max(highest_score, mult_frac(goal->current_value, 10000, goal->target_value)); @@ -2632,17 +2762,20 @@ static unsigned long damos_quota_score(struct damos_quota *quota) return highest_score; } -static void damos_goal_tune_esz_bp_consist(struct damos_quota *quota) +static void damos_goal_tune_esz_bp_consist(struct damon_ctx *c, struct damos *s) { - unsigned long score = damos_quota_score(quota); + struct damos_quota *quota = &s->quota; + unsigned long score = damos_quota_score(c, s); quota->esz_bp = damon_feed_loop_next_input( max(quota->esz_bp, 10000UL), score); } -static void damos_goal_tune_esz_bp_temporal(struct damos_quota *quota) +static void damos_goal_tune_esz_bp_temporal(struct damon_ctx *c, + struct damos *s) { - unsigned long score = damos_quota_score(quota); + struct damos_quota *quota = &s->quota; + unsigned long score = damos_quota_score(c, s); if (score >= 10000) quota->esz_bp = 0; @@ -2655,8 +2788,9 @@ static void damos_goal_tune_esz_bp_temporal(struct damos_quota *quota) /* * Called only if quota->ms, or quota->sz are set, or quota->goals is not empty */ -static void damos_set_effective_quota(struct damos_quota *quota) +static void damos_set_effective_quota(struct damon_ctx *c, struct damos *s) { + struct damos_quota *quota = &s->quota; unsigned long throughput; unsigned long esz = ULONG_MAX; @@ -2667,9 +2801,9 @@ static void damos_set_effective_quota(struct damos_quota *quota) if (!list_empty("a->goals)) { if (quota->goal_tuner == DAMOS_QUOTA_GOAL_TUNER_CONSIST) - damos_goal_tune_esz_bp_consist(quota); + damos_goal_tune_esz_bp_consist(c, s); else if (quota->goal_tuner == DAMOS_QUOTA_GOAL_TUNER_TEMPORAL) - damos_goal_tune_esz_bp_temporal(quota); + damos_goal_tune_esz_bp_temporal(c, s); esz = quota->esz_bp / 10000; } @@ -2718,7 +2852,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s) /* First charge window */ if (!quota->total_charged_sz && !quota->charged_from) { quota->charged_from = jiffies; - damos_set_effective_quota(quota); + damos_set_effective_quota(c, s); if (trace_damos_esz_enabled()) damos_trace_esz(c, s, quota); } @@ -2739,7 +2873,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s) quota->charged_sz = 0; if (trace_damos_esz_enabled()) cached_esz = quota->esz; - damos_set_effective_quota(quota); + damos_set_effective_quota(c, s); if (trace_damos_esz_enabled() && quota->esz != cached_esz) damos_trace_esz(c, s, quota); } diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index bf923709ab91..7e9cd19d5bff 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -1084,6 +1084,14 @@ struct damos_sysfs_qgoal_metric_name damos_sysfs_qgoal_metric_names[] = { .metric = DAMOS_QUOTA_INACTIVE_MEM_BP, .name = "inactive_mem_bp", }, + { + .metric = DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP, + .name = "node_eligible_mem_bp", + }, + { + .metric = DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP, + .name = "node_ineligible_mem_bp", + }, }; static ssize_t target_metric_show(struct kobject *kobj, @@ -2717,6 +2725,10 @@ static int damos_sysfs_add_quota_score( case DAMOS_QUOTA_NODE_MEM_FREE_BP: goal->nid = sysfs_goal->nid; break; + case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: + case DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: + goal->nid = sysfs_goal->nid; + break; case DAMOS_QUOTA_NODE_MEMCG_USED_BP: case DAMOS_QUOTA_NODE_MEMCG_FREE_BP: err = damon_sysfs_memcg_path_to_id( -- 2.43.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-20 19:04 ` [RFC PATCH v4 1/1] " Ravi Jonnalagadda @ 2026-03-21 16:54 ` SeongJae Park 2026-03-23 19:41 ` Ravi Jonnalagadda 0 siblings, 1 reply; 8+ messages in thread From: SeongJae Park @ 2026-03-21 16:54 UTC (permalink / raw) To: Ravi Jonnalagadda Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun On Fri, 20 Mar 2026 12:04:53 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > Add new quota goal metrics for memory tiering that track scheme-eligible > memory distribution across NUMA nodes: > > - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node > - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on > a node The description for the second metric should be "ratio of ineligible memory on a node". > > These complementary metrics enable push-pull migration schemes that > maintain a target memory distribution across different NUMA nodes > representing different memory tiers, based on access patterns defined > by each scheme. > > The metrics iterate scheme-eligible regions and use damon_get_folio() > to determine NUMA node placement of each folio, calculating the ratio > of eligible memory on the specified node versus total eligible memory. > > Suggested-by: SeongJae Park <sj@kernel.org> > Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com> > --- > include/linux/damon.h | 6 ++ > mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++--- > mm/damon/sysfs-schemes.c | 12 +++ > 3 files changed, 164 insertions(+), 12 deletions(-) > > diff --git a/include/linux/damon.h b/include/linux/damon.h > index b1d8fd88a0fc..490918804f85 100644 > --- a/include/linux/damon.h > +++ b/include/linux/damon.h > @@ -193,6 +193,10 @@ enum damos_action { > * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP: MemFree ratio of a node for a cgroup. > * @DAMOS_QUOTA_ACTIVE_MEM_BP: Active to total LRU memory ratio. > * @DAMOS_QUOTA_INACTIVE_MEM_BP: Inactive to total LRU memory ratio. > + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: Scheme-eligible memory ratio of a > + * node. > + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: Scheme-ineligible memory ratio of a > + * node. > * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics. > * > * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported. > @@ -206,6 +210,8 @@ enum damos_quota_goal_metric { > DAMOS_QUOTA_NODE_MEMCG_FREE_BP, > DAMOS_QUOTA_ACTIVE_MEM_BP, > DAMOS_QUOTA_INACTIVE_MEM_BP, > + DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP, > + DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP, > NR_DAMOS_QUOTA_GOAL_METRICS, > }; > > diff --git a/mm/damon/core.c b/mm/damon/core.c > index b9e12865622c..3e0ac65e34a0 100644 > --- a/mm/damon/core.c > +++ b/mm/damon/core.c > @@ -17,6 +17,8 @@ > #include <linux/string.h> > #include <linux/string_choices.h> > > +#include "ops-common.h" > + I don't find a reason to include this, and I'd like to avoid including that in core.c unless it is really necessary. Could you please remove this? Below looks all good for RFC level code to move on to the next stage (dropping RFC tag). :) Thanks, SJ [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-21 16:54 ` SeongJae Park @ 2026-03-23 19:41 ` Ravi Jonnalagadda 2026-03-23 23:54 ` SeongJae Park 0 siblings, 1 reply; 8+ messages in thread From: Ravi Jonnalagadda @ 2026-03-23 19:41 UTC (permalink / raw) To: SeongJae Park Cc: damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun On Sat, Mar 21, 2026 at 9:54 AM SeongJae Park <sj@kernel.org> wrote: > > On Fri, 20 Mar 2026 12:04:53 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > > > Add new quota goal metrics for memory tiering that track scheme-eligible > > memory distribution across NUMA nodes: > > > > - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node > > - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on > > a node > > The description for the second metric should be "ratio of ineligible memory on > a node". > Got it. Will fix the commit message. > > > > These complementary metrics enable push-pull migration schemes that > > maintain a target memory distribution across different NUMA nodes > > representing different memory tiers, based on access patterns defined > > by each scheme. > > > > The metrics iterate scheme-eligible regions and use damon_get_folio() > > to determine NUMA node placement of each folio, calculating the ratio > > of eligible memory on the specified node versus total eligible memory. > > > > Suggested-by: SeongJae Park <sj@kernel.org> > > Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com> > > --- > > include/linux/damon.h | 6 ++ > > mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++--- > > mm/damon/sysfs-schemes.c | 12 +++ > > 3 files changed, 164 insertions(+), 12 deletions(-) > > > > diff --git a/include/linux/damon.h b/include/linux/damon.h > > index b1d8fd88a0fc..490918804f85 100644 > > --- a/include/linux/damon.h > > +++ b/include/linux/damon.h > > @@ -193,6 +193,10 @@ enum damos_action { > > * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP: MemFree ratio of a node for a cgroup. > > * @DAMOS_QUOTA_ACTIVE_MEM_BP: Active to total LRU memory ratio. > > * @DAMOS_QUOTA_INACTIVE_MEM_BP: Inactive to total LRU memory ratio. > > + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: Scheme-eligible memory ratio of a > > + * node. > > + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: Scheme-ineligible memory ratio of a > > + * node. > > * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics. > > * > > * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported. > > @@ -206,6 +210,8 @@ enum damos_quota_goal_metric { > > DAMOS_QUOTA_NODE_MEMCG_FREE_BP, > > DAMOS_QUOTA_ACTIVE_MEM_BP, > > DAMOS_QUOTA_INACTIVE_MEM_BP, > > + DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP, > > + DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP, > > NR_DAMOS_QUOTA_GOAL_METRICS, > > }; > > > > diff --git a/mm/damon/core.c b/mm/damon/core.c > > index b9e12865622c..3e0ac65e34a0 100644 > > --- a/mm/damon/core.c > > +++ b/mm/damon/core.c > > @@ -17,6 +17,8 @@ > > #include <linux/string.h> > > #include <linux/string_choices.h> > > > > +#include "ops-common.h" > > + > > I don't find a reason to include this, and I'd like to avoid including that in > core.c unless it is really necessary. Could you please remove this? > The include was added because the implementation uses damon_get_folio() to determine NUMA node placement of folios when iterating eligible regions. Would you prefer that I move the damon_get_folio() declaration to include/linux/damon.h, or would you suggest a different approach such as adding an ops callback for the node calculation? > Below looks all good for RFC level code to move on to the next stage (dropping > RFC tag). :) > Thank you, SJ! Will send v5 with fixes once I hear back on the above. Best Regards, Ravi. > > Thanks, > SJ > > [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-23 19:41 ` Ravi Jonnalagadda @ 2026-03-23 23:54 ` SeongJae Park 0 siblings, 0 replies; 8+ messages in thread From: SeongJae Park @ 2026-03-23 23:54 UTC (permalink / raw) To: Ravi Jonnalagadda Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun On Mon, 23 Mar 2026 12:41:42 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > On Sat, Mar 21, 2026 at 9:54 AM SeongJae Park <sj@kernel.org> wrote: > > > > On Fri, 20 Mar 2026 12:04:53 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > > > > > Add new quota goal metrics for memory tiering that track scheme-eligible > > > memory distribution across NUMA nodes: > > > > > > - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node > > > - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on > > > a node > > > > The description for the second metric should be "ratio of ineligible memory on > > a node". > > > > Got it. Will fix the commit message. > > > > > > > These complementary metrics enable push-pull migration schemes that > > > maintain a target memory distribution across different NUMA nodes > > > representing different memory tiers, based on access patterns defined > > > by each scheme. > > > > > > The metrics iterate scheme-eligible regions and use damon_get_folio() > > > to determine NUMA node placement of each folio, calculating the ratio > > > of eligible memory on the specified node versus total eligible memory. > > > > > > Suggested-by: SeongJae Park <sj@kernel.org> > > > Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com> > > > --- > > > include/linux/damon.h | 6 ++ > > > mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++--- > > > mm/damon/sysfs-schemes.c | 12 +++ > > > 3 files changed, 164 insertions(+), 12 deletions(-) > > > > > > diff --git a/include/linux/damon.h b/include/linux/damon.h > > > index b1d8fd88a0fc..490918804f85 100644 > > > --- a/include/linux/damon.h > > > +++ b/include/linux/damon.h > > > @@ -193,6 +193,10 @@ enum damos_action { > > > * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP: MemFree ratio of a node for a cgroup. > > > * @DAMOS_QUOTA_ACTIVE_MEM_BP: Active to total LRU memory ratio. > > > * @DAMOS_QUOTA_INACTIVE_MEM_BP: Inactive to total LRU memory ratio. > > > + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: Scheme-eligible memory ratio of a > > > + * node. > > > + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: Scheme-ineligible memory ratio of a > > > + * node. > > > * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics. > > > * > > > * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported. > > > @@ -206,6 +210,8 @@ enum damos_quota_goal_metric { > > > DAMOS_QUOTA_NODE_MEMCG_FREE_BP, > > > DAMOS_QUOTA_ACTIVE_MEM_BP, > > > DAMOS_QUOTA_INACTIVE_MEM_BP, > > > + DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP, > > > + DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP, > > > NR_DAMOS_QUOTA_GOAL_METRICS, > > > }; > > > > > > diff --git a/mm/damon/core.c b/mm/damon/core.c > > > index b9e12865622c..3e0ac65e34a0 100644 > > > --- a/mm/damon/core.c > > > +++ b/mm/damon/core.c > > > @@ -17,6 +17,8 @@ > > > #include <linux/string.h> > > > #include <linux/string_choices.h> > > > > > > +#include "ops-common.h" > > > + > > > > I don't find a reason to include this, and I'd like to avoid including that in > > core.c unless it is really necessary. Could you please remove this? > > > > The include was added because the implementation uses damon_get_folio() to > determine NUMA node placement of folios when iterating eligible regions. Thank you for clarifying, Ravi. > Would you prefer that I move the damon_get_folio() declaration to > include/linux/damon.h, or would you suggest a different approach such as > adding an ops callback for the node calculation? I'd like to keep it mm/damon/ internal if possible. Maybe adding new files, say, mm/damon/common.{c,h} is one option. Just keeping it as is for now with clarification comment (e.g., "including ops-common.h for damon_get_folio()") for now, and revisiting for cleanup in future could also be another option. I slightly prefer the second option at the moment. > > > Below looks all good for RFC level code to move on to the next stage (dropping > > RFC tag). :) > > > > Thank you, SJ! Will send v5 with fixes once I hear back on the above. Sounds good, looking forward to! Thanks, SJ [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-20 19:04 [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics Ravi Jonnalagadda 2026-03-20 19:04 ` [RFC PATCH v4 1/1] " Ravi Jonnalagadda @ 2026-03-21 16:57 ` SeongJae Park 2026-03-23 19:23 ` Ravi Jonnalagadda 1 sibling, 1 reply; 8+ messages in thread From: SeongJae Park @ 2026-03-21 16:57 UTC (permalink / raw) To: Ravi Jonnalagadda Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun Hello Ravi, Thank you for this patch! TL; DR: Other than trivial things I commented below and to the patch, I believe it is time to drop the RFC tag, and work on merging this. On Fri, 20 Mar 2026 12:04:52 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > This patch introduces two new DAMON quota goal metrics for controlling s/DAMON/DAMOS/ ? > memory distribution in heterogeneous memory systems (e.g., DRAM and CXL > memory tiering) using physical address (PA) mode monitoring. > > v3: https://lore.kernel.org/linux-mm/20260223123232.12851-1-ravis.opensrc@gmail.com/ The above link would better to be put on 'Chage since v3' section below. > > Changes since v3: > ================= > > - The first two patches from v3 (goal_tuner initialization fix and > esz=0 quota bypass fix) are now in damon/next. This submission It is not also in mm-unstable :) > contains only the core metrics patch, rebased on top of those fixes. > > - Simplified implementation: removed per-node eligible_bytes array, now > iterates scheme-eligible regions directly for each goal evaluation. > > - Handle regions crossing node boundaries: uses damon_get_folio() to > determine actual NUMA node placement of each folio rather than > assuming uniform node placement within a region. > > - Pass scheme pointer directly to metric calculation functions, avoiding > container_of() derivation from quota pointer. > > - Fixed 80-column wrapping issues. Thank you for addressing all my comments! > > Background and Motivation > ========================= > > In heterogeneous memory systems, controlling memory distribution across > NUMA nodes is essential for performance optimization. This patch enables > system-wide page distribution with target-state goals like "maintain 30% > of scheme-eligible memory on CXL" using PA-mode DAMON schemes. > > What These Metrics Measure > ========================== > > node_eligible_mem_bp: > scheme_eligible_bytes_on_node / total_scheme_eligible_bytes * 10000 > > node_ineligible_mem_bp: > (total - scheme_eligible_bytes_on_node) / total * 10000 > > The metrics are complementary: eligible_bp + ineligible_bp = 10000 bp. > > Two-Scheme Setup for Hot Page Distribution > ========================================== > > For maintaining 30% of hot memory on CXL (node 1): I think it could help easy reading if the above sentence also explains node 0 is DRAM. For example, For maintaining hot memory on DRAM (node 0) and CXL (node 1) in 7:3 ratio: > > PUSH scheme: migrate_hot from node 0 -> node 1 > goal: node_ineligible_mem_bp, nid=0, target=3000 > "Push hot pages out until 30% of hot memory is NOT on DRAM" Seems the sentence assumes the actor is in DRAM. It was not very clear to me. How about making it clear? E.g., "Move hot pages from DRAM to CXL, if more than 70% of hot data is in DRAM" > > PULL scheme: migrate_hot from node 1 -> node 0 > goal: node_eligible_mem_bp, nid=0, target=7000 > "Pull hot pages back until 70% of hot memory IS on DRAM" If the above example is good for you, to be consistent with it, how about rewording like below? "Move hot pages from CXL to DRAM, if less than 70% of hot data is in DRAM" > > The complementary goals create a feedback loop that converges to the > target distribution. > > Dependencies > ============ > > This patch is based on SJ's damon/next branch which includes the > TEMPORAL goal tuner required for these metrics. Your test might be depend on the feature. But this patch series itself is not, as users could also use it with CONSIST tuner? Also, as I mentioned above, the feature is now also in mm-unstable tree. > > Testing Results > =============== > > Functionally tested on a two-node heterogeneous memory system with DRAM > (node 0) and CXL memory (node 1). Used PUSH+PULL scheme configuration > with migrate_hot action to maintain a target hot memory ratio between > the two tiers. > > With the TEMPORAL goal tuner, the system converges quickly to the target > distribution. The tuner drives esz to maximum when under goal and to > zero once the goal is met, forming a simple on/off feedback loop that > stabilizes at the desired ratio. > > With the CONSIST tuner, the scheme still converges but more slowly, as > it migrates and then throttles itself based on quota feedback. The time > to reach the goal varies depending on workload intensity. Sounds reasonable! Do you plan to further evaluate some performance metrics? I'd not strongly request that, but it would be very nice if we can have that. Regardless of your answer to the above question, I think the current code and the test is good enough to consider merging this. I suggest dropping the RFC tag from the next spin. Thank you for doing this, Ravi! Thanks, SJ [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-21 16:57 ` [RFC PATCH v4 0/1] " SeongJae Park @ 2026-03-23 19:23 ` Ravi Jonnalagadda 2026-03-23 23:45 ` SeongJae Park 0 siblings, 1 reply; 8+ messages in thread From: Ravi Jonnalagadda @ 2026-03-23 19:23 UTC (permalink / raw) To: SeongJae Park Cc: damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun On Sat, Mar 21, 2026 at 9:57 AM SeongJae Park <sj@kernel.org> wrote: > > Hello Ravi, > > > Thank you for this patch! TL; DR: Other than trivial things I commented below > and to the patch, I believe it is time to drop the RFC tag, and work on merging > this. > Thanks, SJ, for the prompt and detailed feedback! > On Fri, 20 Mar 2026 12:04:52 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > > > This patch introduces two new DAMON quota goal metrics for controlling > > s/DAMON/DAMOS/ ? > Will fix it. > > memory distribution in heterogeneous memory systems (e.g., DRAM and CXL > > memory tiering) using physical address (PA) mode monitoring. > > > > v3: https://lore.kernel.org/linux-mm/20260223123232.12851-1-ravis.opensrc@gmail.com/ > > The above link would better to be put on 'Chage since v3' section below. > Got it. Will take care of it next time. > > > > Changes since v3: > > ================= > > > > - The first two patches from v3 (goal_tuner initialization fix and > > esz=0 quota bypass fix) are now in damon/next. This submission > > It is not also in mm-unstable :) Good to know. Will mention this in the next version. > > > contains only the core metrics patch, rebased on top of those fixes. > > > > - Simplified implementation: removed per-node eligible_bytes array, now > > iterates scheme-eligible regions directly for each goal evaluation. > > > > - Handle regions crossing node boundaries: uses damon_get_folio() to > > determine actual NUMA node placement of each folio rather than > > assuming uniform node placement within a region. > > > > - Pass scheme pointer directly to metric calculation functions, avoiding > > container_of() derivation from quota pointer. > > > > - Fixed 80-column wrapping issues. > > Thank you for addressing all my comments! > > > > > Background and Motivation > > ========================= > > > > In heterogeneous memory systems, controlling memory distribution across > > NUMA nodes is essential for performance optimization. This patch enables > > system-wide page distribution with target-state goals like "maintain 30% > > of scheme-eligible memory on CXL" using PA-mode DAMON schemes. > > > > What These Metrics Measure > > ========================== > > > > node_eligible_mem_bp: > > scheme_eligible_bytes_on_node / total_scheme_eligible_bytes * 10000 > > > > node_ineligible_mem_bp: > > (total - scheme_eligible_bytes_on_node) / total * 10000 > > > > The metrics are complementary: eligible_bp + ineligible_bp = 10000 bp. > > > > Two-Scheme Setup for Hot Page Distribution > > ========================================== > > > > For maintaining 30% of hot memory on CXL (node 1): > > I think it could help easy reading if the above sentence also explains > node 0 is DRAM. For example, > > For maintaining hot memory on DRAM (node 0) and CXL (node 1) in 7:3 ratio: Good suggestion, will clarify the node mapping. > > > > > PUSH scheme: migrate_hot from node 0 -> node 1 > > goal: node_ineligible_mem_bp, nid=0, target=3000 > > "Push hot pages out until 30% of hot memory is NOT on DRAM" > > Seems the sentence assumes the actor is in DRAM. It was not very clear to me. > How about making it clear? E.g., > > "Move hot pages from DRAM to CXL, if more than 70% of hot data is in DRAM" Got it. Will use your suggested wording. > > > > > PULL scheme: migrate_hot from node 1 -> node 0 > > goal: node_eligible_mem_bp, nid=0, target=7000 > > "Pull hot pages back until 70% of hot memory IS on DRAM" > > If the above example is good for you, to be consistent with it, how about > rewording like below? > > "Move hot pages from CXL to DRAM, if less than 70% of hot data is in DRAM" Agreed. Will reword this too. > > > > > The complementary goals create a feedback loop that converges to the > > target distribution. > > > > Dependencies > > ============ > > > > This patch is based on SJ's damon/next branch which includes the > > TEMPORAL goal tuner required for these metrics. > > Your test might be depend on the feature. But this patch series itself is not, > as users could also use it with CONSIST tuner? > Correct, the metrics work with both tuners. Will reword to clarify that testing used TEMPORAL but the patch itself does not depend on it. > Also, as I mentioned above, the feature is now also in mm-unstable tree. > > > > > Testing Results > > =============== > > > > Functionally tested on a two-node heterogeneous memory system with DRAM > > (node 0) and CXL memory (node 1). Used PUSH+PULL scheme configuration > > with migrate_hot action to maintain a target hot memory ratio between > > the two tiers. > > > > With the TEMPORAL goal tuner, the system converges quickly to the target > > distribution. The tuner drives esz to maximum when under goal and to > > zero once the goal is met, forming a simple on/off feedback loop that > > stabilizes at the desired ratio. > > > > With the CONSIST tuner, the scheme still converges but more slowly, as > > it migrates and then throttles itself based on quota feedback. The time > > to reach the goal varies depending on workload intensity. > > Sounds reasonable! > > Do you plan to further evaluate some performance metrics? I'd not strongly > request that, but it would be very nice if we can have that. > Yes, I am planning to run additional tests. I will send v5 addressing all the review comments and dropping the RFC tag. Results will follow as the testing progresses. > Regardless of your answer to the above question, I think the current code and > the test is good enough to consider merging this. I suggest dropping the RFC > tag from the next spin. > > Thank you for doing this, Ravi! > Thank you! Will drop the RFC tag for v5. > > Thanks, > SJ > Best Regards, Ravi. > [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics 2026-03-23 19:23 ` Ravi Jonnalagadda @ 2026-03-23 23:45 ` SeongJae Park 0 siblings, 0 replies; 8+ messages in thread From: SeongJae Park @ 2026-03-23 23:45 UTC (permalink / raw) To: Ravi Jonnalagadda Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm, corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun On Mon, 23 Mar 2026 12:23:49 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote: > On Sat, Mar 21, 2026 at 9:57 AM SeongJae Park <sj@kernel.org> wrote: [...] > > > > > > Changes since v3: > > > ================= > > > > > > - The first two patches from v3 (goal_tuner initialization fix and > > > esz=0 quota bypass fix) are now in damon/next. This submission > > > > It is not also in mm-unstable :) What I really wanted to say is, s/not/now/ > > Good to know. Will mention this in the next version. I think Ravi understood what I really wanted to mean, though. [...] > Thank you! Will drop the RFC tag for v5. Looking forward to! Thanks, SJ [...] ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-03-23 23:54 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-20 19:04 [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics Ravi Jonnalagadda 2026-03-20 19:04 ` [RFC PATCH v4 1/1] " Ravi Jonnalagadda 2026-03-21 16:54 ` SeongJae Park 2026-03-23 19:41 ` Ravi Jonnalagadda 2026-03-23 23:54 ` SeongJae Park 2026-03-21 16:57 ` [RFC PATCH v4 0/1] " SeongJae Park 2026-03-23 19:23 ` Ravi Jonnalagadda 2026-03-23 23:45 ` SeongJae Park
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox