mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Subsystems (3)
v6 cover mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Changes since v5:
=================
https://lore.kernel.org/linux-mm/[email protected]/
- Rebased onto mm-new instead of damon/next for sashiko review
- Removed Reported-by/Closes tags per maintainer feedback (not needed for bugs found before merge)
Changes since v4:
=================
https://lore.kernel.org/linux-mm/[email protected]/
- Fixed commit message description for DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP per review feedback
- Added clarifying comment for ops-common.h include (for damon_get_folio())
- Fixed build error when CONFIG_DAMON_PADDR is disabled by adding #ifdef CONFIG_DAMON_PADDR guards around functions using damon_get_folio()
- Dropped RFC tag per maintainer feedback
This patch is based on top of mm-new.
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 such as "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
These metrics are complementary: eligible_bp + ineligible_bp = 10000 bp.
Two-Scheme Setup for Hot Page Distribution
==========================================
For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:
PUSH scheme: migrate_hot from node 0 -> node 1
goal: node_ineligible_mem_bp, nid=0, target=3000
"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
"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.
Testing Results
===============
Functionally tested on a two-node heterogeneous memory system with DRAM (node 0) and CXL memory (node 1). A PUSH+PULL scheme configuration using migrate_hot actions was used to reach a target hot memory ratio between the two tiers. Testing used the TEMPORAL goal tuner available in damon/next and mm-unstable.
With the TEMPORAL 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.
Note: These metrics work with both TEMPORAL and CONSIST goal tuners.
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 | 188 ++++++++++++++++++++++++++++++++++++--- mm/damon/sysfs-schemes.c | 12 +++ 3 files changed, 192 insertions(+), 14 deletions(-)
base-commit: b47b4fa4c232ee36aae58630e9d6520e35d33f3a
Signature · 1 line
2.43.0
PATCH v6 1/1 mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
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 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.
The implementation is guarded by CONFIG_DAMON_PADDR since damon_get_folio() is only available when physical address space monitoring is enabled.
--- include/linux/damon.h | 6 ++ mm/damon/core.c | 188 ++++++++++++++++++++++++++++++++++++--- mm/damon/sysfs-schemes.c | 12 +++ 3 files changed, 192 insertions(+), 14 deletions(-)
include/linux/damon.h +6 -0
@@ -159,6 +159,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.
@@ -172,6 +176,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, };
mm/damon/core.c +174 -14
268 lines not on this page · raw message
mm/damon/sysfs-schemes.c +12 -0
@@ -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,
@@ -2655,6 +2663,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(
Signature · 1 line
2.43.0
SeongJae Park
maintainerRe: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Ravi, thank you for reposting this patch after the rebase. This time sashiko was able to review this, and found good points including things that deserve another revision of this patch.
Forwarding full sashiko review in a reply format with my inline comments below, for sharing details of my view and doing followup discussions via mails. Ravi, could you please reply?
Quoted 16 lines
# review url: https://sashiko.dev/#/patchset/[email protected] # start of sashiko.dev inline review commit 5f6ea8da06d136b84d97827777acf2b07047d42c Author: Ravi Jonnalagadda <[email protected]> mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metricsThis commit adds quota goal metrics for tracking scheme-eligible and ineligible memory distribution across NUMA nodes. It iterates over scheme-eligible regions and uses
damon_get_folio()to determine placement.Quoted 3 lines
mm/damon/core.c +0
-0[ ... ]
Quoted 12 lines
mm/damon/core.c
Quoted 7 lines
mm/damon/core.c +7
-0+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 ;Can
total_eligibleandnode_eligibleoverflow on 32-bit architectures? Since these accumulators track raw physical bytes, regions spanning multiple gigabytes might wrap around the 32-bit unsigned long limit. Would it be safer to use u64 or track the counts in pages instead?
Makes sense. Ravi, could we update these to use phys_addr_t?
Quoted 13 lines
mm/damon/core.c
Quoted 8 lines
mm/damon/core.c +7
-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 ;Should this loop also check
damos_core_filter_out()? By only checking__damos_valid_target(), it seems memory explicitly excluded by user-defined region filters (like target ID or memcg limits) is still counted as eligible, which might inflate the total and affect the quota tuning loop.
No, we intentionally defined "eligible" based on only the access pattern. We may be able to extend this to apply filters in future, if we find a use case. But, for now, I'd suggest keeping this as is for now.
Quoted 10 lines
mm/damon/core.c
Quoted 6 lines
mm/damon/core.c +5
-0+ +/* 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) {Could this unbounded loop cause CPU soft lockups? Since DAMON regions can span hundreds of gigabytes, executing millions of folio lookups sequentially without a
cond_resched()could monopolize the CPU.
Good point. Most DAMOS action implementations are also doing cond_resched() per region. Ravi, could we add cond_resched() per region to this function, too?
Quoted 11 lines
mm/damon/core.c
Quoted 5 lines
mm/damon/core.c +4
-0+struct folio *folio; +unsigned long folio_sz, counted; + + folio =damon_get_folio (PHYS_PFN (addr));What happens if this metric is assigned to a DAMON context configured for virtual address space monitoring? If the context uses
DAMON_OPS_VADDR, passing a user-space virtual address toPHYS_PFN()might cause invalid memory accesses or out-of-bounds page struct reads. Should this code explicitly verify the operations type first?
Good finding. We intend to support only paddr ops. But there is no guard for using this on vaddr ops configuration. Ravi, could we add underlying ops check? I think damon_commit_ctx() is a good place to add that. The check could be something like below?
'''
mm/damon/core.c +13 -0
@@ -1515,10 +1515,23 @@ static int damon_commit_sample_control(int damon_commit_ctx (struct damon_ctx *dst,struct damon_ctx *src) {int err; +struct damos *scheme; +struct damos_quota_goal *goal; dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_region_sz))return -EINVAL ; +if (src->ops.id !=DAMON_OPS_PADDR ) { +damon_for_each_scheme (scheme, src) { +damos_for_each_quota_goal (goal, &scheme->quota) { +switch (goal->metric) { +case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP : +case DAMOS_QUOTA_NODE_INELIGIBLE_MEMPBP : +return -EINVAL ; + } + } + } + } err =damon_commit_schemes (dst, src);if (err)
'''
Quoted 19 lines
mm/damon/core.c
Quoted 13 lines
mm/damon/core.c +12
-0+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));Does this accurately calculate the remaining bytes if the region starts at an unaligned offset within a large folio?
folio_size()returns the full size of the folio, so this calculation might overestimate the eligible bytes by not accounting for the initial offset within the folio.
Quoted 9 lines
mm/damon/core.c
Quoted 5 lines
mm/damon/core.c +5
-0+ total_eligible += counted; +if (folio_nid (folio) == nid) + node_eligible += counted; + + addr += folio_sz;Can this pointer advancement overshoot the end of the current folio? If addr was unaligned, adding the full
folio_szwill skip past the beginning of the next contiguous physical memory folio.
Above two points make sense to me. Ravi, could we fix these?
Quoted 28 lines
Quoted 9 lines
mm/damon/core.c +8
-0+folio_put (folio); + } + } + } + + *total = total_eligible; +return node_eligible; +}[ ... ]
Quoted 16 lines
mm/damon/core.c +16
-0+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 */
Quoted 8 lines
mm/damon/core.c
Quoted 2 lines
mm/damon/core.c +2
-0+return 10000 -mult_frac (node_eligible,10000 , total_eligible); +}Does this return value match the documented metric? The formula computes the percentage of the system's eligible memory located on other NUMA nodes, rather than the amount of actual ineligible (filtered out) memory residing on the target node. Could this semantic mismatch cause confusion when configuring quota policies?
Nice catch. The name and the documentation are confusing. We actually confused a few times in previous revisions, and I'm again confused now. IIUC, the current implementation is the intended and right one for the given use case, though. If my understanding is correct, how about renaming DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP to DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_COMPLEMENT, and updating the documentation together? Ravi, what do you think?
Quoted 4 lines
# end of sashiko.dev inline review # review url: https://sashiko.dev/#/patchset/[email protected]
Thanks,
SJ
# hkml [1] generated a draft of this mail. You can regenerate # this using below command: # # hkml patch sashiko_dev --for_forwarding \ # [email protected] #
Re: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Quoted 10 lines · SeongJae Park
Ravi, thank you for reposting this patch after the rebase. This time sashiko was able to review this, and found good points including things that deserve another revision of this patch.
Forwarding full sashiko review in a reply format with my inline comments below, for sharing details of my view and doing followup discussions via mails. Ravi, could you please reply?
Thanks SJ, providing your comments on top of sashiko's review is very helpful.
Quoted 29 lines
Quoted 16 lines
# review url: https://sashiko.dev/#/patchset/[email protected] # start of sashiko.dev inline review commit 5f6ea8da06d136b84d97827777acf2b07047d42c Author: Ravi Jonnalagadda <[email protected]> mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metricsThis commit adds quota goal metrics for tracking scheme-eligible and ineligible memory distribution across NUMA nodes. It iterates over scheme-eligible regions and uses
damon_get_folio()to determine placement.Quoted 3 lines
mm/damon/core.c +0
-0[ ... ]
Quoted 12 lines
mm/damon/core.c
Quoted 7 lines
mm/damon/core.c +7
-0+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 ;Can
total_eligibleandnode_eligibleoverflow on 32-bit architectures? Since these accumulators track raw physical bytes, regions spanning multiple gigabytes might wrap around the 32-bit unsigned long limit. Would it be safer to use u64 or track the counts in pages instead?
Quoted 1 line
Makes sense. Ravi, could we update these to use
phys_addr_t?
Agreed. I'll update total_eligible, node_eligible, and the function return type to use phys_addr_t throughout damos_calc_eligible_bytes().
Quoted 15 lines
Quoted 14 lines
mm/damon/core.c
Quoted 9 lines
mm/damon/core.c +7
-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 ;Should this loop also check
damos_core_filter_out()? By only checking__damos_valid_target(), it seems memory explicitly excluded by user-defined region filters (like target ID or memcg limits) is still counted as eligible, which might inflate the total and affect the quota tuning loop.
Quoted 4 lines
No, we intentionally defined "eligible" based on only the access pattern. We may be able to extend this to apply filters in future, if we find a use case. But, for now, I'd suggest keeping this as is for now.
Got it. Will keep it as is.
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
mm/damon/core.c +5
-0+ +/* 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) {
Quoted 7 lines
Quoted 3 lines
Could this unbounded loop cause CPU soft lockups? Since DAMON regions can span hundreds of gigabytes, executing millions of folio lookups sequentially without a
cond_resched()could monopolize the CPU.Good point. Most DAMOS action implementations are also doing
cond_resched()per region. Ravi, could we addcond_resched()per region to this function, too?
Will add cond_resched() at the end of each region's processing.
Quoted 13 lines
Quoted 7 lines
mm/damon/core.c
Quoted 6 lines
mm/damon/core.c +4
-0+struct folio *folio; +unsigned long folio_sz, counted; + + folio =damon_get_folio (PHYS_PFN (addr));Quoted 5 lines
What happens if this metric is assigned to a DAMON context configured for virtual address space monitoring? If the context uses
DAMON_OPS_VADDR, passing a user-space virtual address toPHYS_PFN()might cause invalid memory accesses or out-of-bounds page struct reads. Should this code explicitly verify the operations type first?
Quoted 5 lines
Good finding. We intend to support only paddr ops. But there is no guard for using this on vaddr ops configuration. Ravi, could we add underlying ops check? I think
damon_commit_ctx()is a good place to add that. The check could be something like below?
I plan to add the ops type check directly in the metric functions (damos_get_node_eligible_mem_bp and its counterpart) rather than in damon_commit_ctx(). The functions will return 0 early
if c->ops.id != DAMON_OPS_PADDR.
That said, if you prefer the damon_commit_ctx() validation approach to reject the configuration outright, I can implement it that way instead. Please let me know your preference.
Quoted 54 lines
'''
mm/damon/core.c +13
-0@@ -1515,10 +1515,23 @@ static int damon_commit_sample_control(int damon_commit_ctx (struct damon_ctx *dst,struct damon_ctx *src) {int err; +struct damos *scheme; +struct damos_quota_goal *goal; dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_region_sz))return -EINVAL ; +if (src->ops.id !=DAMON_OPS_PADDR ) { +damon_for_each_scheme (scheme, src) { +damos_for_each_quota_goal (goal, &scheme->quota) { +switch (goal->metric) { +case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP : +case DAMOS_QUOTA_NODE_INELIGIBLE_MEMPBP : +return -EINVAL ; + } + } + } + } err =damon_commit_schemes (dst, src);if (err)'''
Quoted 25 lines
mm/damon/core.c
Quoted 13 lines
mm/damon/core.c +12
-0+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));Does this accurately calculate the remaining bytes if the region starts at an unaligned offset within a large folio?
folio_size()returns the full size of the folio, so this calculation might overestimate the eligible bytes by not accounting for the initial offset within the folio.Quoted 5 lines
mm/damon/core.c +5
-0+ total_eligible += counted; +if (folio_nid (folio) == nid) + node_eligible += counted; + + addr += folio_sz;
Quoted 6 lines
Quoted 3 lines
Can this pointer advancement overshoot the end of the current folio? If addr was unaligned, adding the full
folio_szwill skip past the beginning of the next contiguous physical memory folio.Above two points make sense to me. Ravi, could we fix these?
Will fix it. Will calculate the exact overlap between the region [addr, end_addr) and the folio's actual range.
Quoted 37 lines
Quoted 28 lines
Quoted 9 lines
mm/damon/core.c +8
-0+folio_put (folio); + } + } + } + + *total = total_eligible; +return node_eligible; +}[ ... ]
Quoted 16 lines
mm/damon/core.c +16
-0+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 */ Quoted 8 lines
mm/damon/core.c
Quoted 2 lines
mm/damon/core.c +2
-0+return 10000 -mult_frac (node_eligible,10000 , total_eligible); +}Does this return value match the documented metric? The formula computes the percentage of the system's eligible memory located on other NUMA nodes, rather than the amount of actual ineligible (filtered out) memory residing on the target node. Could this semantic mismatch cause confusion when configuring quota policies?
Quoted 8 lines
Nice catch. The name and the documentation are confusing. We actually confused a few times in previous revisions, and I'm again confused now. IIUC, the current implementation is the intended and right one for the given use case, though. If my understanding is correct, how about renaming
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPtoDAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_COMPLEMENT, and updating the documentation together? Ravi, what do you think?
Agreed, the current name is confusing. How aboutDAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_OFFNODE?
The rationale is that this metric measures "eligible memory that is off this node" (i.e., on other nodes).
I think "offnode" conveys the physical meaning more directly than "complement".
That said, I'm happy to go with "complement" if you prefer.
both are clearer than "ineligible".
Quoted 9 lines
Quoted 4 lines
# end of sashiko.dev inline review # review url: https://sashiko.dev/#/patchset/[email protected]Thanks,
SJ
Best Regards,
Ravi.
Quoted 6 lines
# hkml [1] generated a draft of this mail. You can regenerate # this using below command: # # hkml patch sashiko_dev --for_forwarding \ # [email protected] #
SeongJae Park
maintainerRe: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Quoted 7 lines · On Mon, 6 Apr 2026 12:47:56 -0700 Ravi Jonnalagadda <[email protected]>…
Quoted 6 lines · SeongJae Park
Ravi, thank you for reposting this patch after the rebase. This time sashiko was able to review this, and found good points including things that deserve another revision of this patch.
Quoted 6 lines
Quoted 4 lines
Forwarding full sashiko review in a reply format with my inline comments below, for sharing details of my view and doing followup discussions via mails. Ravi, could you please reply?
Thanks SJ, providing your comments on top of sashiko's review is very helpful.
I'm glad to hear that it is working for you :)
[...]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
+static unsigned long damos_calc_eligible_bytes(struct
damon_ctx*c,Quoted 2 lines
(quoted diff) +2
-0+ struct damos *s, int nid, unsigned long *total) +{
[...]
Quoted 17 lines
Quoted 11 lines
Quoted 10 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ struct folio *folio; + unsigned long folio_sz, counted; + + folio = damon_get_folio(PHYS_PFN(addr));What happens if this metric is assigned to a DAMON context configured for virtual address space monitoring? If the context uses
DAMON_OPS_VADDR, passing a user-space virtual address toPHYS_PFN()might cause invalid memory accesses or out-of-bounds page struct reads. Should this code explicitly verify the operations type first?Quoted 5 lines
Good finding. We intend to support only paddr ops. But there is no guard for using this on vaddr ops configuration. Ravi, could we add underlying ops check? I think
damon_commit_ctx()is a good place to add that. The check could be something like below?
Quoted 8 lines
I plan to add the ops type check directly in the metric functions (
damos_get_node_eligible_mem_bpand its counterpart) rather than indamon_commit_ctx(). The functions will return 0 early
ifc->ops.id!=DAMON_OPS_PADDR.That said, if you prefer the
damon_commit_ctx()validation approach to reject the configuration outright, I can implement it that way instead. Please let me know your preference.
I'd prefer damon_commit_ctx() validation approach since it would give users more clear message of the failure.
Quoted 29 lines
Quoted 29 lines
'''
mm/damon/core.c +13
-0@@ -1515,10 +1515,23 @@ static int damon_commit_sample_control(int damon_commit_ctx (struct damon_ctx *dst,struct damon_ctx *src) {int err; +struct damos *scheme; +struct damos_quota_goal *goal; dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_region_sz))return -EINVAL ; +if (src->ops.id !=DAMON_OPS_PADDR ) { +damon_for_each_scheme (scheme, src) { +damos_for_each_quota_goal (goal, &scheme->quota) { +switch (goal->metric) { +case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP : +case DAMOS_QUOTA_NODE_INELIGIBLE_MEMPBP : +return -EINVAL ; + } + } + } + } err =damon_commit_schemes (dst, src);if (err)'''
[...]
Quoted 22 lines
Quoted 10 lines
Quoted 9 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ /* Compute ineligible ratio directly: 10000 - eligible_bp */ + return 10000 - mult_frac(node_eligible, 10000, total_eligible); +}Does this return value match the documented metric? The formula computes the percentage of the system's eligible memory located on other NUMA nodes, rather than the amount of actual ineligible (filtered out) memory residing on the target node. Could this semantic mismatch cause confusion when configuring quota policies?
Quoted 8 lines
Nice catch. The name and the documentation are confusing. We actually confused a few times in previous revisions, and I'm again confused now. IIUC, the current implementation is the intended and right one for the given use case, though. If my understanding is correct, how about renaming
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPtoDAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_COMPLEMENT, and updating the documentation together? Ravi, what do you think?Agreed, the current name is confusing. How about
DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_OFFNODE?
Quoted 6 lines
The rationale is that this metric measures "eligible memory that is off this node" (i.e., on other nodes).
I think "offnode" conveys the physical meaning more directly than "complement".
That said, I'm happy to go with "complement" if you prefer.
both are clearer than "ineligible".
Thank you for the nice suggestion. I like "offnode" term. But I think having "node" twice on the name is not really efficient for people who print code on papers. What about DAMOS_QUOTA_OFFNODE_ELIGIBLE_MEM_BP?
But... Maybe more importantly... Now I realize this means that offnode_eligible_mem_bp with target nid 0 is just same to node_eligible_mem_bp with target nid 1, on your test setup. Maybe we don't really need offnode_eligible_mem_bp? That is, your test setup could be like below.
'''
For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:
PUSH scheme: migrate_hot from node 0 -> node 1
goal: node_eligible_mem_bp, nid=1, target=3000
"Move hot pages from DRAM to CXL if less thatn 30% of hot data is
in CXL"
PULL scheme: migrate_hot from node 1 -> node 0
goal: node_eligible_mem_bp, nid=0, target=7000
"Move hot pages from CXL to DRAM if less than 70% of hot data is
in DRAM"'''
And the schemes are more easy to read and understand for me. This seems even straightforward to scale for >2 nodes. For example, if we want hot memory distribution of 5:3:2 to nodes 0:1:2,
Two schemes for migrating hot pages out of node 0
- migrate_hot from node 0 -> node 1
- goal: node_eligible_mem_bp, nid=1, target=3000
- migrate_hot from node 0 -> node 2
- goal: node_eligible_mem_bp, nid=2, target=2000
Two schemes for migrating hot pages out of node 1
- migrate_hot from node 1 -> node 0
- goal: node_eligible_mem_bp, nid=0, target=5000
- migrate_hot from node 1 -> node 2
- goal: node_eligible_mem_bp, nid=2, target=2000
Two schemes for migrating hot pages out of node 2
- migrate_hot from node 2 -> node 0
- goal: node_eligible_mem_bp, nid=0, target=5000
- migrate_hot from node 2 -> node 1
- goal: node_eligible_mem_bp, nid=1, target=3000
Do you think this makes sense? If it makes sense and works for your use case, what about dropping the offnode goal type?
Thanks,
SJ
[...]
SeongJae Park
maintainerRe: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Adding another thought at the end of the mail without cutting the previous unrelated questions, so that Ravi can answer all my questions at once.
Quoted 151 lines · On Mon, 6 Apr 2026 17:13:08 -0700 SeongJae Park <[email protected]> wrote:
Quoted 7 lines · On Mon, 6 Apr 2026 12:47:56 -0700 Ravi Jonnalagadda <[email protected]>…
Quoted 6 lines · SeongJae Park
Ravi, thank you for reposting this patch after the rebase. This time sashiko was able to review this, and found good points including things that deserve another revision of this patch.
Quoted 6 lines
Quoted 4 lines
Forwarding full sashiko review in a reply format with my inline comments below, for sharing details of my view and doing followup discussions via mails. Ravi, could you please reply?
Thanks SJ, providing your comments on top of sashiko's review is very helpful.
I'm glad to hear that it is working for you :)
[...]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
+static unsigned long damos_calc_eligible_bytes(struct
damon_ctx*c,Quoted 2 lines
(quoted diff) +2
-0+ struct damos *s, int nid, unsigned long *total) +{[...]
Quoted 17 lines
Quoted 11 lines
Quoted 10 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ struct folio *folio; + unsigned long folio_sz, counted; + + folio = damon_get_folio(PHYS_PFN(addr));What happens if this metric is assigned to a DAMON context configured for virtual address space monitoring? If the context uses
DAMON_OPS_VADDR, passing a user-space virtual address toPHYS_PFN()might cause invalid memory accesses or out-of-bounds page struct reads. Should this code explicitly verify the operations type first?Quoted 5 lines
Good finding. We intend to support only paddr ops. But there is no guard for using this on vaddr ops configuration. Ravi, could we add underlying ops check? I think
damon_commit_ctx()is a good place to add that. The check could be something like below?Quoted 8 lines
I plan to add the ops type check directly in the metric functions (
damos_get_node_eligible_mem_bpand its counterpart) rather than indamon_commit_ctx(). The functions will return 0 early
ifc->ops.id!=DAMON_OPS_PADDR.That said, if you prefer the
damon_commit_ctx()validation approach to reject the configuration outright, I can implement it that way instead. Please let me know your preference.I'd prefer
damon_commit_ctx()validation approach since it would give users more clear message of the failure.Quoted 29 lines
Quoted 29 lines
'''
mm/damon/core.c +13
-0@@ -1515,10 +1515,23 @@ static int damon_commit_sample_control(int damon_commit_ctx (struct damon_ctx *dst,struct damon_ctx *src) {int err; +struct damos *scheme; +struct damos_quota_goal *goal; dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_region_sz))return -EINVAL ; +if (src->ops.id !=DAMON_OPS_PADDR ) { +damon_for_each_scheme (scheme, src) { +damos_for_each_quota_goal (goal, &scheme->quota) { +switch (goal->metric) { +case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP : +case DAMOS_QUOTA_NODE_INELIGIBLE_MEMPBP : +return -EINVAL ; + } + } + } + } err =damon_commit_schemes (dst, src);if (err)'''
[...]
Quoted 22 lines
Quoted 10 lines
Quoted 9 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ /* Compute ineligible ratio directly: 10000 - eligible_bp */ + return 10000 - mult_frac(node_eligible, 10000, total_eligible); +}Does this return value match the documented metric? The formula computes the percentage of the system's eligible memory located on other NUMA nodes, rather than the amount of actual ineligible (filtered out) memory residing on the target node. Could this semantic mismatch cause confusion when configuring quota policies?
Quoted 8 lines
Nice catch. The name and the documentation are confusing. We actually confused a few times in previous revisions, and I'm again confused now. IIUC, the current implementation is the intended and right one for the given use case, though. If my understanding is correct, how about renaming
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPtoDAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_COMPLEMENT, and updating the documentation together? Ravi, what do you think?Agreed, the current name is confusing. How about
DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_OFFNODE?Quoted 6 lines
The rationale is that this metric measures "eligible memory that is off this node" (i.e., on other nodes).
I think "offnode" conveys the physical meaning more directly than "complement".
That said, I'm happy to go with "complement" if you prefer.
both are clearer than "ineligible".Thank you for the nice suggestion. I like "offnode" term. But I think having "node" twice on the name is not really efficient for people who print code on papers. What about
DAMOS_QUOTA_OFFNODE_ELIGIBLE_MEM_BP?But... Maybe more importantly... Now I realize this means that
offnode_eligible_mem_bpwith target nid 0 is just same tonode_eligible_mem_bpwith target nid 1, on your test setup. Maybe we don't really needoffnode_eligible_mem_bp? That is, your test setup could be like below.'''
For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:PUSH scheme: migrate_hot from node 0 -> node 1 goal: node_eligible_mem_bp, nid=1, target=3000 "Move hot pages from DRAM to CXL if less thatn 30% of hot data is in CXL" PULL scheme: migrate_hot from node 1 -> node 0 goal: node_eligible_mem_bp, nid=0, target=7000 "Move hot pages from CXL to DRAM if less than 70% of hot data is in DRAM"'''
And the schemes are more easy to read and understand for me. This seems even straightforward to scale for >2 nodes. For example, if we want hot memory distribution of 5:3:2 to nodes 0:1:2,
Two schemes for migrating hot pages out of node 0
-migrate_hotfrom node 0 -> node 1
- goal:node_eligible_mem_bp, nid=1, target=3000
-migrate_hotfrom node 0 -> node 2
- goal:node_eligible_mem_bp, nid=2, target=2000Two schemes for migrating hot pages out of node 1
-migrate_hotfrom node 1 -> node 0
- goal:node_eligible_mem_bp, nid=0, target=5000
-migrate_hotfrom node 1 -> node 2
- goal:node_eligible_mem_bp, nid=2, target=2000
Quoted 8 lines
Two schemes for migrating hot pages out of node 2
-migrate_hotfrom node 2 -> node 0
- goal:node_eligible_mem_bp, nid=0, target=5000
-migrate_hotfrom node 2 -> node 1
- goal:node_eligible_mem_bp, nid=1, target=3000Do you think this makes sense? If it makes sense and works for your use case, what about dropping the offnode goal type?
Now I recall I suggested the offnode metric because I suggested to run a kdamond per node. That is, having one kdamond that monitors only node 0 and migrate hot memory to node 1, and another kdamond that monitors only node 1 and migrate hot memory to node 0. And I suggested to do so because I knew it is suboptimal to run DAMOS schemes with node filter.
We made a change [1] for making that more optimum, though. The change is now in mm-stable, so hopefully it will be available from 7.1-rc1. So I believe the single quota goal metric should work now. Ravi, could you share what you think?
[1] commit e1ace69c33ec ("mm/damon/core: set quota-score histogram with core filters")
Thanks,
SJ
[...]
Re: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Quoted 172 lines · SeongJae Park
Adding another thought at the end of the mail without cutting the previous unrelated questions, so that Ravi can answer all my questions at once.
Quoted 151 lines · On Mon, 6 Apr 2026 17:13:08 -0700 SeongJae Park <[email protected]> wrote:
Quoted 7 lines · On Mon, 6 Apr 2026 12:47:56 -0700 Ravi Jonnalagadda <[email protected]>…
Quoted 6 lines · SeongJae Park
Ravi, thank you for reposting this patch after the rebase. This time sashiko was able to review this, and found good points including things that deserve another revision of this patch.
Quoted 6 lines
Quoted 4 lines
Forwarding full sashiko review in a reply format with my inline comments below, for sharing details of my view and doing followup discussions via mails. Ravi, could you please reply?
Thanks SJ, providing your comments on top of sashiko's review is very helpful.
I'm glad to hear that it is working for you :)
[...]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
+static unsigned long damos_calc_eligible_bytes(struct
damon_ctx*c,Quoted 2 lines
(quoted diff) +2
-0+ struct damos *s, int nid, unsigned long *total) +{[...]
Quoted 17 lines
Quoted 11 lines
Quoted 10 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ struct folio *folio; + unsigned long folio_sz, counted; + + folio = damon_get_folio(PHYS_PFN(addr));What happens if this metric is assigned to a DAMON context configured for virtual address space monitoring? If the context uses
DAMON_OPS_VADDR, passing a user-space virtual address toPHYS_PFN()might cause invalid memory accesses or out-of-bounds page struct reads. Should this code explicitly verify the operations type first?Quoted 5 lines
Good finding. We intend to support only paddr ops. But there is no guard for using this on vaddr ops configuration. Ravi, could we add underlying ops check? I think
damon_commit_ctx()is a good place to add that. The check could be something like below?Quoted 8 lines
I plan to add the ops type check directly in the metric functions (
damos_get_node_eligible_mem_bpand its counterpart) rather than indamon_commit_ctx(). The functions will return 0 early
ifc->ops.id!=DAMON_OPS_PADDR.That said, if you prefer the
damon_commit_ctx()validation approach to reject the configuration outright, I can implement it that way instead. Please let me know your preference.I'd prefer
damon_commit_ctx()validation approach since it would give users more clear message of the failure.Quoted 29 lines
Quoted 29 lines
'''
mm/damon/core.c +13
-0@@ -1515,10 +1515,23 @@ static int damon_commit_sample_control(int damon_commit_ctx (struct damon_ctx *dst,struct damon_ctx *src) {int err; +struct damos *scheme; +struct damos_quota_goal *goal; dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_region_sz))return -EINVAL ; +if (src->ops.id !=DAMON_OPS_PADDR ) { +damon_for_each_scheme (scheme, src) { +damos_for_each_quota_goal (goal, &scheme->quota) { +switch (goal->metric) { +case DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP : +case DAMOS_QUOTA_NODE_INELIGIBLE_MEMPBP : +return -EINVAL ; + } + } + } + } err =damon_commit_schemes (dst, src);if (err)'''
[...]
Quoted 22 lines
Quoted 10 lines
Quoted 9 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ /* Compute ineligible ratio directly: 10000 - eligible_bp */ + return 10000 - mult_frac(node_eligible, 10000, total_eligible); +}Does this return value match the documented metric? The formula computes the percentage of the system's eligible memory located on other NUMA nodes, rather than the amount of actual ineligible (filtered out) memory residing on the target node. Could this semantic mismatch cause confusion when configuring quota policies?
Quoted 8 lines
Nice catch. The name and the documentation are confusing. We actually confused a few times in previous revisions, and I'm again confused now. IIUC, the current implementation is the intended and right one for the given use case, though. If my understanding is correct, how about renaming
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPtoDAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_COMPLEMENT, and updating the documentation together? Ravi, what do you think?Agreed, the current name is confusing. How about
DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP_OFFNODE?Quoted 6 lines
The rationale is that this metric measures "eligible memory that is off this node" (i.e., on other nodes).
I think "offnode" conveys the physical meaning more directly than "complement".
That said, I'm happy to go with "complement" if you prefer.
both are clearer than "ineligible".Thank you for the nice suggestion. I like "offnode" term. But I think having "node" twice on the name is not really efficient for people who print code on papers. What about
DAMOS_QUOTA_OFFNODE_ELIGIBLE_MEM_BP?But... Maybe more importantly... Now I realize this means that
offnode_eligible_mem_bpwith target nid 0 is just same tonode_eligible_mem_bpwith target nid 1, on your test setup. Maybe we don't really needoffnode_eligible_mem_bp? That is, your test setup could be like below.'''
For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:PUSH scheme: migrate_hot from node 0 -> node 1 goal: node_eligible_mem_bp, nid=1, target=3000 "Move hot pages from DRAM to CXL if less thatn 30% of hot data is in CXL" PULL scheme: migrate_hot from node 1 -> node 0 goal: node_eligible_mem_bp, nid=0, target=7000 "Move hot pages from CXL to DRAM if less than 70% of hot data is in DRAM"'''
And the schemes are more easy to read and understand for me. This seems even straightforward to scale for >2 nodes. For example, if we want hot memory distribution of 5:3:2 to nodes 0:1:2,
Two schemes for migrating hot pages out of node 0
-migrate_hotfrom node 0 -> node 1
- goal:node_eligible_mem_bp, nid=1, target=3000
-migrate_hotfrom node 0 -> node 2
- goal:node_eligible_mem_bp, nid=2, target=2000Two schemes for migrating hot pages out of node 1
-migrate_hotfrom node 1 -> node 0
- goal:node_eligible_mem_bp, nid=0, target=5000
-migrate_hotfrom node 1 -> node 2
- goal:node_eligible_mem_bp, nid=2, target=2000Quoted 8 lines
Two schemes for migrating hot pages out of node 2
-migrate_hotfrom node 2 -> node 0
- goal:node_eligible_mem_bp, nid=0, target=5000
-migrate_hotfrom node 2 -> node 1
- goal:node_eligible_mem_bp, nid=1, target=3000Do you think this makes sense? If it makes sense and works for your use case, what about dropping the offnode goal type?
Now I recall I suggested the offnode metric because I suggested to run a kdamond per node. That is, having one kdamond that monitors only node 0 and migrate hot memory to node 1, and another kdamond that monitors only node 1 and migrate hot memory to node 0. And I suggested to do so because I knew it is suboptimal to run DAMOS schemes with node filter.
Quoted 5 lines
We made a change [1] for making that more optimum, though. The change is now in mm-stable, so hopefully it will be available from 7.1-rc1. So I believe the single quota goal metric should work now. Ravi, could you share what you think?
Yes SJ. I think we can make it work with single goal now that the below commit is part of mainline. will give it a try and post an update.
Quoted 7 lines
[1] commit
e1ace69c33ec("mm/damon/core: set quota-score histogram with core filters")Thanks,
SJ[...]
SeongJae Park
maintainerRe: (sashiko review) [PATCH v6 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
Quoted 1 line · On Tue, 7 Apr 2026 19:33:43 -0700 Ravi Jonnalagadda <[email protected]>…
On Tue, Apr 7, 2026 at 9:05 AM SeongJae Park <[email protected]> wrote:
[...]
Quoted 3 lines
Yes SJ. I think we can make it work with single goal now that the below commit is part of mainline. will give it a try and post an update.
Sounds good, please don't hesitate asking any questions.
Thanks,
SJ
[...]
SeongJae Park
maintainerHello Ravi,
Quoted 5 lines · On Sun, 5 Apr 2026 11:42:46 -0700 Ravi Jonnalagadda <[email protected]>…
Changes since v5:
=================
https://lore.kernel.org/linux-mm/[email protected]/- Rebased onto mm-new instead of damon/next for sashiko review
Thank you for doing this. sashiko was able to review and find some good points. I shared the full review with my opinions as a reply to the patch 1. Please check and reply.
Quoted 27 lines
- Removed Reported-by/Closes tags per maintainer feedback (not needed for bugs found before merge)
Changes since v4:
=================
https://lore.kernel.org/linux-mm/[email protected]/- Fixed commit message description for
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPper review feedback
- Added clarifying comment forops-common.hinclude (fordamon_get_folio())
- Fixed build error whenCONFIG_DAMON_PADDRis disabled by adding #ifdefCONFIG_DAMON_PADDRguards around functions usingdamon_get_folio()
- Dropped RFC tag per maintainer feedbackThis patch is based on top of mm-new.
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 such as "maintain 30% of scheme-eligible memory on CXL" using PA-mode DAMON schemes.
What These Metrics Measure
==========================
Quoted 7 lines
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 * 10000These metrics are complementary:
eligible_bp+ineligible_bp= 10000 bp.
As I mentioned on sashiko review, I now think node_ineligible_mem_bp is a confusing name, and thinking a new name, maybe node_eligible_mem_bp_complement is better. Let's further discuss on sashiko review reply thread.
Quoted 40 lines
Two-Scheme Setup for Hot Page Distribution
==========================================For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:
PUSH scheme: migrate_hot from node 0 -> node 1 goal: node_ineligible_mem_bp, nid=0, target=3000 "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 "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.
Testing Results
===============Functionally tested on a two-node heterogeneous memory system with DRAM (node 0) and CXL memory (node 1). A PUSH+PULL scheme configuration using
migrate_hotactions was used to reach a target hot memory ratio between the two tiers. Testing used the TEMPORAL goal tuner available in damon/next and mm-unstable.With the TEMPORAL 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.
Note: These metrics work with both TEMPORAL and CONSIST goal tuners.
Quoted 8 lines
Ravi Jonnalagadda (1):
mm/damon: addnode_eligible_mem_bpandnode_ineligible_mem_bpgoal
metricsinclude/linux/damon.h | 6 ++ mm/damon/core.c | 188 ++++++++++++++++++++++++++++++++++++--- mm/damon/sysfs-schemes.c | 12 +++ 3 files changed, 192 insertions(+), 14 deletions(-)
Btw, having a cover letter for single patch looks odd. Why don't you add this cover letter to the patch's commit message?
Thanks,
SJ
[...]
Hi SJ,
I will address your comments and the feedback from sashiko's review in the next version of the patch.
Regarding the cover letter, I originally included it to provide context on the general methodology. However, I agree that it is unnecessary for a single patch. I will move the relevant content to the commit message and drop the cover letter in the next iteration.
Thanks,
Ravi Jonnalagadda
Quoted 119 lines · SeongJae Park
Hello Ravi,
Quoted 3 lines · On Sun, 5 Apr 2026 11:42:46 -0700 Ravi Jonnalagadda <…
Changes since v5:
=================https://lore.kernel.org/linux-mm/[email protected]/
Quoted 2 lines
- Rebased onto mm-new instead of damon/next for sashiko review
Thank you for doing this. sashiko was able to review and find some good points. I shared the full review with my opinions as a reply to the patch 1.
Please check and reply.Quoted 6 lines
- Removed Reported-by/Closes tags per maintainer feedback (not needed for bugs found before merge)
Changes since v4:
=================https://lore.kernel.org/linux-mm/[email protected]/
Quoted 4 lines
- Fixed commit message description for
DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BPper review feedback
- Added clarifying comment forops-common.hinclude (for
damon_get_folio())Quoted 2 lines
- Fixed build error when
CONFIG_DAMON_PADDRis disabled by adding #ifdefCONFIG_DAMON_PADDRguards around functions using
damon_get_folio()Quoted 15 lines
- Dropped RFC tag per maintainer feedback
This patch is based on top of mm-new.
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 such as "maintain 30% of scheme-eligible memory on CXL" using PA-mode DAMON schemes.
What These Metrics Measure
==========================Quoted 7 lines
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 * 10000These metrics are complementary:
eligible_bp+ineligible_bp= 10000 bp.As I mentioned on sashiko review, I now think
node_ineligible_mem_bpis a confusing name, and thinking a new name, maybenode_eligible_mem_bp_complement
is better. Let's further discuss on sashiko review reply thread.Quoted 40 lines
Two-Scheme Setup for Hot Page Distribution
==========================================For maintaining hot memory on DRAM (node 0) and CXL (node 1) in a 7:3 ratio:
PUSH scheme: migrate_hot from node 0 -> node 1 goal: node_ineligible_mem_bp, nid=0, target=3000 "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 "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.
Testing Results
===============Functionally tested on a two-node heterogeneous memory system with DRAM (node 0) and CXL memory (node 1). A PUSH+PULL scheme configuration using
migrate_hotactions was used to reach a target hot memory ratio between the two tiers. Testing used the TEMPORAL goal tuner available in damon/next and mm-unstable.With the TEMPORAL 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.
Note: These metrics work with both TEMPORAL and CONSIST goal tuners.
Quoted 8 lines
Ravi Jonnalagadda (1):
mm/damon: addnode_eligible_mem_bpandnode_ineligible_mem_bpgoal
metricsinclude/linux/damon.h | 6 ++ mm/damon/core.c | 188 ++++++++++++++++++++++++++++++++++++--- mm/damon/sysfs-schemes.c | 12 +++ 3 files changed, 192 insertions(+), 14 deletions(-)Btw, having a cover letter for single patch looks odd. Why don't you add this
cover letter to the patch's commit message?Thanks,
SJ[...]