* [RFC PATCH v2 1/4] mm: compaction: parameterize fragmentation score by order
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
@ 2026-10-01 0:14 ` Bo Zhang
2026-10-01 0:14 ` [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction Bo Zhang
` (4 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Bo Zhang @ 2026-10-01 0:14 UTC (permalink / raw)
To: akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
The proactive compaction fragmentation score functions are hardwired to
COMPACTION_HPAGE_ORDER (typically order-9 for 2MB THP). To later allow
proactive compaction to target other orders (e.g. smaller mTHP orders),
generalize these helpers to take an explicit order argument:
- fragmentation_score_zone(zone, order)
- fragmentation_score_zone_weighted(zone, order)
- fragmentation_score_node(pgdat, order)
All callers pass COMPACTION_HPAGE_ORDER, so this patch is a pure
refactor with no functional change.
Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
---
mm/compaction.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index 4994e200bbec..ecd3e6cf54fc 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2208,16 +2208,16 @@ static bool kswapd_is_running(pg_data_t *pgdat)
/*
* A zone's fragmentation score is the external fragmentation wrt to the
- * COMPACTION_HPAGE_ORDER. It returns a value in the range [0, 100].
+ * given order. It returns a value in the range [0, 100].
*/
-static unsigned int fragmentation_score_zone(struct zone *zone)
+static unsigned int fragmentation_score_zone(struct zone *zone, unsigned int order)
{
- return extfrag_for_order(zone, COMPACTION_HPAGE_ORDER);
+ return extfrag_for_order(zone, order);
}
/*
* A weighted zone's fragmentation score is the external fragmentation
- * wrt to the COMPACTION_HPAGE_ORDER scaled by the zone's size. It
+ * wrt to the given order scaled by the zone's size. It
* returns a value in the range [0, 100].
*
* The scaling factor ensures that proactive compaction focuses on larger
@@ -2225,11 +2225,11 @@ static unsigned int fragmentation_score_zone(struct zone *zone)
* ZONE_DMA32. For smaller zones, the score value remains close to zero,
* and thus never exceeds the high threshold for proactive compaction.
*/
-static unsigned int fragmentation_score_zone_weighted(struct zone *zone)
+static unsigned int fragmentation_score_zone_weighted(struct zone *zone, unsigned int order)
{
unsigned long score;
- score = zone->present_pages * fragmentation_score_zone(zone);
+ score = zone->present_pages * fragmentation_score_zone(zone, order);
return div64_ul(score, zone->zone_pgdat->node_present_pages + 1);
}
@@ -2240,7 +2240,7 @@ static unsigned int fragmentation_score_zone_weighted(struct zone *zone)
* the node's score falls below the low threshold, or one of the back-off
* conditions is met.
*/
-static unsigned int fragmentation_score_node(pg_data_t *pgdat)
+static unsigned int fragmentation_score_node(pg_data_t *pgdat, unsigned int order)
{
unsigned int score = 0;
int zoneid;
@@ -2251,7 +2251,7 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat)
zone = &pgdat->node_zones[zoneid];
if (!populated_zone(zone))
continue;
- score += fragmentation_score_zone_weighted(zone);
+ score += fragmentation_score_zone_weighted(zone, order);
}
return score;
@@ -2269,12 +2269,13 @@ static unsigned int fragmentation_score_wmark(bool low)
static bool should_proactive_compact_node(pg_data_t *pgdat)
{
int wmark_high;
+ unsigned int order = COMPACTION_HPAGE_ORDER;
if (!sysctl_compaction_proactiveness || kswapd_is_running(pgdat))
return false;
wmark_high = fragmentation_score_wmark(false);
- return fragmentation_score_node(pgdat) > wmark_high;
+ return fragmentation_score_node(pgdat, order) > wmark_high;
}
static enum compact_result __compact_finished(struct compact_control *cc)
@@ -2305,13 +2306,14 @@ static enum compact_result __compact_finished(struct compact_control *cc)
if (cc->proactive_compaction) {
int score, wmark_low;
+ unsigned int order = COMPACTION_HPAGE_ORDER;
pg_data_t *pgdat;
pgdat = cc->zone->zone_pgdat;
if (kswapd_is_running(pgdat))
return COMPACT_PARTIAL_SKIPPED;
- score = fragmentation_score_zone(cc->zone);
+ score = fragmentation_score_zone(cc->zone, order);
wmark_low = fragmentation_score_wmark(true);
if (score > wmark_low)
@@ -3237,10 +3239,11 @@ static int kcompactd(void *p)
timeout = default_timeout;
if (should_proactive_compact_node(pgdat)) {
unsigned int prev_score, score;
+ unsigned int order = COMPACTION_HPAGE_ORDER;
- prev_score = fragmentation_score_node(pgdat);
+ prev_score = fragmentation_score_node(pgdat, order);
compact_node(pgdat, true);
- score = fragmentation_score_node(pgdat);
+ score = fragmentation_score_node(pgdat, order);
/*
* Defer proactive compaction if the fragmentation
* score did not go down i.e. no progress made.
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
2026-10-01 0:14 ` [RFC PATCH v2 1/4] mm: compaction: parameterize fragmentation score by order Bo Zhang
@ 2026-10-01 0:14 ` Bo Zhang
2026-10-19 8:12 ` Dev Jain
2026-10-01 0:14 ` [RFC PATCH v2 3/4] mm: compaction: skip isolating large folios that already satisfy mTHP Bo Zhang
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Bo Zhang @ 2026-10-01 0:14 UTC (permalink / raw)
To: akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
Proactive compaction triggers against COMPACTION_HPAGE_ORDER (order-9),
which is too heavyweight and misdirected for mTHP systems where the
pressure is on smaller orders like order-2.
Add compact_hpage_order() to return the highest always-enabled anonymous
mTHP order, and use it as the proactive compaction target in
should_proactive_compact_node(), __compact_finished() and kcompactd().
Fragmentation scores are not comparable across orders, a small order
scores much lower for the same state, so scale the proactive watermarks
down in proportion to the target order, otherwise order-2 would rarely
reach the order-9 threshold.
Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
---
mm/compaction.c | 40 ++++++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index ecd3e6cf54fc..3928a5483efc 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -24,6 +24,7 @@
#include <linux/page_owner.h>
#include <linux/psi.h>
#include <linux/cpuset.h>
+#include <linux/huge_mm.h>
#include "page_alloc.h"
#include "internal.h"
@@ -81,6 +82,17 @@ static inline bool is_via_compact_memory(int order) { return false; }
#define COMPACTION_HPAGE_ORDER (PMD_SHIFT - PAGE_SHIFT)
#endif
+static inline int compact_hpage_order(void)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ unsigned long orders = READ_ONCE(huge_anon_orders_always);
+
+ if (orders)
+ return __fls(orders);
+#endif
+ return COMPACTION_HPAGE_ORDER;
+}
+
static struct page *mark_allocated_noprof(struct page *page, unsigned int order, gfp_t gfp_flags)
{
post_alloc_hook(page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
@@ -2257,24 +2269,36 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat, unsigned int orde
return score;
}
-static unsigned int fragmentation_score_wmark(bool low)
+/*
+ * Fragmentation scores are not comparable across orders: a lower order
+ * scores much lower than a higher order for the same fragmentation state.
+ * Scale the watermark proportionally to the target order so a small order
+ * can still trigger proactive compaction; COMPACTION_HPAGE_ORDER keeps the
+ * original threshold.
+ */
+static unsigned int fragmentation_score_wmark(bool low, unsigned int order)
{
- unsigned int wmark_low, leeway;
+ unsigned int wmark_low, leeway, wmark;
wmark_low = 100U - sysctl_compaction_proactiveness;
leeway = min(10U, wmark_low / 2);
- return low ? wmark_low : min(wmark_low + leeway, 100U);
+ wmark = low ? wmark_low : min(wmark_low + leeway, 100U);
+
+ if (order < COMPACTION_HPAGE_ORDER)
+ wmark = wmark * order / COMPACTION_HPAGE_ORDER;
+
+ return wmark;
}
static bool should_proactive_compact_node(pg_data_t *pgdat)
{
int wmark_high;
- unsigned int order = COMPACTION_HPAGE_ORDER;
+ unsigned int order = compact_hpage_order();
if (!sysctl_compaction_proactiveness || kswapd_is_running(pgdat))
return false;
- wmark_high = fragmentation_score_wmark(false);
+ wmark_high = fragmentation_score_wmark(false, order);
return fragmentation_score_node(pgdat, order) > wmark_high;
}
@@ -2306,7 +2330,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
if (cc->proactive_compaction) {
int score, wmark_low;
- unsigned int order = COMPACTION_HPAGE_ORDER;
+ unsigned int order = compact_hpage_order();
pg_data_t *pgdat;
pgdat = cc->zone->zone_pgdat;
@@ -2314,7 +2338,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
return COMPACT_PARTIAL_SKIPPED;
score = fragmentation_score_zone(cc->zone, order);
- wmark_low = fragmentation_score_wmark(true);
+ wmark_low = fragmentation_score_wmark(true, order);
if (score > wmark_low)
ret = COMPACT_CONTINUE;
@@ -3239,7 +3263,7 @@ static int kcompactd(void *p)
timeout = default_timeout;
if (should_proactive_compact_node(pgdat)) {
unsigned int prev_score, score;
- unsigned int order = COMPACTION_HPAGE_ORDER;
+ unsigned int order = compact_hpage_order();
prev_score = fragmentation_score_node(pgdat, order);
compact_node(pgdat, true);
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-01 0:14 ` [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction Bo Zhang
@ 2026-10-19 8:12 ` Dev Jain
2026-10-19 14:50 ` Xueyuan Chen
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Dev Jain @ 2026-10-19 8:12 UTC (permalink / raw)
To: Bo Zhang, akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
On 01/10/26 5:44 am, Bo Zhang wrote:
> Proactive compaction triggers against COMPACTION_HPAGE_ORDER (order-9),
> which is too heavyweight and misdirected for mTHP systems where the
> pressure is on smaller orders like order-2.
>
> Add compact_hpage_order() to return the highest always-enabled anonymous
> mTHP order, and use it as the proactive compaction target in
> should_proactive_compact_node(), __compact_finished() and kcompactd().
>
> Fragmentation scores are not comparable across orders, a small order
> scores much lower for the same state, so scale the proactive watermarks
> down in proportion to the target order, otherwise order-2 would rarely
> reach the order-9 threshold.
>
> Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
> ---
> mm/compaction.c | 40 ++++++++++++++++++++++++++++++++--------
> 1 file changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/mm/compaction.c b/mm/compaction.c
> index ecd3e6cf54fc..3928a5483efc 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -24,6 +24,7 @@
> #include <linux/page_owner.h>
> #include <linux/psi.h>
> #include <linux/cpuset.h>
> +#include <linux/huge_mm.h>
> #include "page_alloc.h"
> #include "internal.h"
>
> @@ -81,6 +82,17 @@ static inline bool is_via_compact_memory(int order) { return false; }
> #define COMPACTION_HPAGE_ORDER (PMD_SHIFT - PAGE_SHIFT)
> #endif
>
> +static inline int compact_hpage_order(void)
> +{
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> + unsigned long orders = READ_ONCE(huge_anon_orders_always);
> +
> + if (orders)
> + return __fls(orders);
> +#endif
> + return COMPACTION_HPAGE_ORDER;
> +}
> +
> static struct page *mark_allocated_noprof(struct page *page, unsigned int order, gfp_t gfp_flags)
> {
> post_alloc_hook(page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
> @@ -2257,24 +2269,36 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat, unsigned int orde
> return score;
> }
>
> -static unsigned int fragmentation_score_wmark(bool low)
> +/*
> + * Fragmentation scores are not comparable across orders: a lower order
> + * scores much lower than a higher order for the same fragmentation state.
> + * Scale the watermark proportionally to the target order so a small order
> + * can still trigger proactive compaction; COMPACTION_HPAGE_ORDER keeps the
> + * original threshold.
> + */
> +static unsigned int fragmentation_score_wmark(bool low, unsigned int order)
> {
> - unsigned int wmark_low, leeway;
> + unsigned int wmark_low, leeway, wmark;
>
> wmark_low = 100U - sysctl_compaction_proactiveness;
> leeway = min(10U, wmark_low / 2);
> - return low ? wmark_low : min(wmark_low + leeway, 100U);
> + wmark = low ? wmark_low : min(wmark_low + leeway, 100U);
> +
> + if (order < COMPACTION_HPAGE_ORDER)
> + wmark = wmark * order / COMPACTION_HPAGE_ORDER;
> +
> + return wmark;
> }
I wonder if this function should be left alone?
compaction_proactiveness, as I understand is given as a sysfs knob to
ensure that the user can control how much power they want to invest into
compacting. So suppose the value is 20, and the highest mTHP order is
only 2.
This gives wmark = 90 * 2 / 9 = 20. So, even if 80% of the memory can
serve order-2 allocations, we will still perform compaction for order-2.
This seems "extremely proactive" :)
>
> static bool should_proactive_compact_node(pg_data_t *pgdat)
> {
> int wmark_high;
> - unsigned int order = COMPACTION_HPAGE_ORDER;
> + unsigned int order = compact_hpage_order();
>
> if (!sysctl_compaction_proactiveness || kswapd_is_running(pgdat))
> return false;
>
> - wmark_high = fragmentation_score_wmark(false);
> + wmark_high = fragmentation_score_wmark(false, order);
> return fragmentation_score_node(pgdat, order) > wmark_high;
> }
>
> @@ -2306,7 +2330,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
>
> if (cc->proactive_compaction) {
> int score, wmark_low;
> - unsigned int order = COMPACTION_HPAGE_ORDER;
> + unsigned int order = compact_hpage_order();
> pg_data_t *pgdat;
>
> pgdat = cc->zone->zone_pgdat;
> @@ -2314,7 +2338,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
> return COMPACT_PARTIAL_SKIPPED;
>
> score = fragmentation_score_zone(cc->zone, order);
> - wmark_low = fragmentation_score_wmark(true);
> + wmark_low = fragmentation_score_wmark(true, order);
>
> if (score > wmark_low)
> ret = COMPACT_CONTINUE;
> @@ -3239,7 +3263,7 @@ static int kcompactd(void *p)
> timeout = default_timeout;
> if (should_proactive_compact_node(pgdat)) {
> unsigned int prev_score, score;
> - unsigned int order = COMPACTION_HPAGE_ORDER;
> + unsigned int order = compact_hpage_order();
>
> prev_score = fragmentation_score_node(pgdat, order);
> compact_node(pgdat, true);
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-19 8:12 ` Dev Jain
@ 2026-10-19 14:50 ` Xueyuan Chen
2026-10-19 15:03 ` Bo Zhang
2026-10-19 15:47 ` Bo Zhang
2 siblings, 0 replies; 13+ messages in thread
From: Xueyuan Chen @ 2026-10-19 14:50 UTC (permalink / raw)
To: dev.jain, zhangbo56
Cc: akpm, vbabka, david, surenb, mhocko, brendan.jackman, hannes,
ziy, ljs, liam, rppt, qi.zheng, shakeel.butt, kasong, baohua,
axelrasmussen, yuanchu, weixugc, zhaonanzhe, lipengfei28,
linux-mm, linux-kernel, zhangbo0325, Xueyuan Chen
On Mon, Oct 19, 2026 at 01:42:55PM +0530, Dev Jain wrote:
>
>
>On 01/10/26 5:44 am, Bo Zhang wrote:
>> Proactive compaction triggers against COMPACTION_HPAGE_ORDER (order-9),
>> which is too heavyweight and misdirected for mTHP systems where the
>> pressure is on smaller orders like order-2.
>>
>> Add compact_hpage_order() to return the highest always-enabled anonymous
>> mTHP order, and use it as the proactive compaction target in
>> should_proactive_compact_node(), __compact_finished() and kcompactd().
>>
>> Fragmentation scores are not comparable across orders, a small order
>> scores much lower for the same state, so scale the proactive watermarks
>> down in proportion to the target order, otherwise order-2 would rarely
>> reach the order-9 threshold.
>>
>> Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
>> ---
>> mm/compaction.c | 40 ++++++++++++++++++++++++++++++++--------
>> 1 file changed, 32 insertions(+), 8 deletions(-)
>>
>> diff --git a/mm/compaction.c b/mm/compaction.c
>> index ecd3e6cf54fc..3928a5483efc 100644
>> --- a/mm/compaction.c
>> +++ b/mm/compaction.c
>> @@ -24,6 +24,7 @@
>> #include <linux/page_owner.h>
>> #include <linux/psi.h>
>> #include <linux/cpuset.h>
>> +#include <linux/huge_mm.h>
>> #include "page_alloc.h"
>> #include "internal.h"
>>
>> @@ -81,6 +82,17 @@ static inline bool is_via_compact_memory(int order) { return false; }
>> #define COMPACTION_HPAGE_ORDER (PMD_SHIFT - PAGE_SHIFT)
>> #endif
>>
>> +static inline int compact_hpage_order(void)
>> +{
>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>> + unsigned long orders = READ_ONCE(huge_anon_orders_always);
>> +
>> + if (orders)
>> + return __fls(orders);
>> +#endif
>> + return COMPACTION_HPAGE_ORDER;
>> +}
>> +
>> static struct page *mark_allocated_noprof(struct page *page, unsigned int order, gfp_t gfp_flags)
>> {
>> post_alloc_hook(page, order, __GFP_MOVABLE, ALLOC_DEFAULT);
>> @@ -2257,24 +2269,36 @@ static unsigned int fragmentation_score_node(pg_data_t *pgdat, unsigned int orde
>> return score;
>> }
>>
>> -static unsigned int fragmentation_score_wmark(bool low)
>> +/*
>> + * Fragmentation scores are not comparable across orders: a lower order
>> + * scores much lower than a higher order for the same fragmentation state.
>> + * Scale the watermark proportionally to the target order so a small order
>> + * can still trigger proactive compaction; COMPACTION_HPAGE_ORDER keeps the
>> + * original threshold.
>> + */
>> +static unsigned int fragmentation_score_wmark(bool low, unsigned int order)
>> {
>> - unsigned int wmark_low, leeway;
>> + unsigned int wmark_low, leeway, wmark;
>>
>> wmark_low = 100U - sysctl_compaction_proactiveness;
>> leeway = min(10U, wmark_low / 2);
>> - return low ? wmark_low : min(wmark_low + leeway, 100U);
>> + wmark = low ? wmark_low : min(wmark_low + leeway, 100U);
>> +
>> + if (order < COMPACTION_HPAGE_ORDER)
>> + wmark = wmark * order / COMPACTION_HPAGE_ORDER;
>> +
>> + return wmark;
>> }
>
>I wonder if this function should be left alone?
>
>compaction_proactiveness, as I understand is given as a sysfs knob to
>ensure that the user can control how much power they want to invest into
>compacting. So suppose the value is 20, and the highest mTHP order is
>only 2.
>
>This gives wmark = 90 * 2 / 9 = 20. So, even if 80% of the memory can
>serve order-2 allocations, we will still perform compaction for order-2.
>This seems "extremely proactive" :)
My understanding is that compaction for lower orders is cheaper, so lower
thresholds could help reduce mTHP allocation fallbacks at an acceptable
cost. Is that the idea?
>
>>
>> static bool should_proactive_compact_node(pg_data_t *pgdat)
>> {
>> int wmark_high;
>> - unsigned int order = COMPACTION_HPAGE_ORDER;
>> + unsigned int order = compact_hpage_order();
>>
>> if (!sysctl_compaction_proactiveness || kswapd_is_running(pgdat))
>> return false;
>>
>> - wmark_high = fragmentation_score_wmark(false);
>> + wmark_high = fragmentation_score_wmark(false, order);
>> return fragmentation_score_node(pgdat, order) > wmark_high;
>> }
>>
>> @@ -2306,7 +2330,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
>>
>> if (cc->proactive_compaction) {
>> int score, wmark_low;
>> - unsigned int order = COMPACTION_HPAGE_ORDER;
>> + unsigned int order = compact_hpage_order();
>> pg_data_t *pgdat;
>>
>> pgdat = cc->zone->zone_pgdat;
>> @@ -2314,7 +2338,7 @@ static enum compact_result __compact_finished(struct compact_control *cc)
>> return COMPACT_PARTIAL_SKIPPED;
>>
>> score = fragmentation_score_zone(cc->zone, order);
>> - wmark_low = fragmentation_score_wmark(true);
>> + wmark_low = fragmentation_score_wmark(true, order);
>>
>> if (score > wmark_low)
>> ret = COMPACT_CONTINUE;
>> @@ -3239,7 +3263,7 @@ static int kcompactd(void *p)
>> timeout = default_timeout;
>> if (should_proactive_compact_node(pgdat)) {
>> unsigned int prev_score, score;
>> - unsigned int order = COMPACTION_HPAGE_ORDER;
>> + unsigned int order = compact_hpage_order();
>>
>> prev_score = fragmentation_score_node(pgdat, order);
>> compact_node(pgdat, true);
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-19 8:12 ` Dev Jain
2026-10-19 14:50 ` Xueyuan Chen
@ 2026-10-19 15:03 ` Bo Zhang
2026-10-20 6:48 ` Dev Jain
2026-10-19 15:47 ` Bo Zhang
2 siblings, 1 reply; 13+ messages in thread
From: Bo Zhang @ 2026-10-19 15:03 UTC (permalink / raw)
To: dev.jain
Cc: akpm, vbabka, david, surenb, mhocko, brendan.jackman, hannes,
ziy, ljs, liam, rppt, qi.zheng, shakeel.butt, kasong, baohua,
axelrasmussen, yuanchu, weixugc, zhaonanzhe, lipengfei28,
linux-mm, linux-kernel, Bo Zhang
On 19/10/26 1:42 pm, Dev Jain wrote:
> I wonder if this function should be left alone?
>
> compaction_proactiveness, as I understand is given as a sysfs knob to
> ensure that the user can control how much power they want to invest into
> compacting. So suppose the value is 20, and the highest mTHP order is
> only 2. This gives wmark = 90 * 2 / 9 = 20. So, even if 80% of the memory
> can serve order-2 allocations, we will still perform compaction for
> order-2. This seems "extremely proactive" :)
Thanks a lot for looking at this closely, and you are right that the
scaling factor is the weakest part of this patch. I called it out as an
open question in the cover letter and I don't have a solid theoretical
basis for the linear order/COMPACTION_HPAGE_ORDER form.
What pushed me towards scaling the watermark at all was the opposite
problem on the measurement side: without any scaling, the order-9
threshold is essentially never reached for a small order, so proactive
compaction effectively never runs for order-2.
I instrumented fragmentation_score_node() for order-2 on an 8G,
data=journal kernel-build workload and sampled it at ~100ms. On the
unpatched kernel the order-2 score looks like this:
order-2 score (unpatched, same workload):
mean 17.3
p90 47
p99 91
max 100
fraction of time the score exceeds a given threshold:
> 90 (unscaled, the current order-9 wmark): 1.0%
> 20 (scaled down to order-2): 27.2%
So with the current (unscaled) watermark, the order-2 score crosses the
trigger only 1% of the time, which in practice proactive compaction almost
never fires for order-2.
That said, your example shows the linear scaling clearly overshoots in
the other direction: a scaled wmark of ~20 can keep compacting while a
large fraction of memory is already usable, which is not what the
proactiveness knob is supposed to express. So I agree the current formula
is not the right answer.
I'd appreciate your thoughts on the direction here. A couple of options
I can see:
1. Leave fragmentation_score_wmark() alone and instead make the score
itself order-aware / normalized, so that a given proactiveness value
maps to a comparable amount of work regardless of the target order.
This keeps the knob's meaning intact.
2. Keep scaling the watermark but with a floor / non-linear mapping so
it cannot collapse to a value that triggers when memory is clearly
sufficient.
I haven't settled on either yet and would rather hear which direction you
think makes more sense before reworking it.
Also, thanks for the review on patch 4 -- good to know the
costly/non-costly split seems like a reasonable compromise.
Thanks,
Bo
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-19 15:03 ` Bo Zhang
@ 2026-10-20 6:48 ` Dev Jain
0 siblings, 0 replies; 13+ messages in thread
From: Dev Jain @ 2026-10-20 6:48 UTC (permalink / raw)
To: Bo Zhang
Cc: akpm, vbabka, david, surenb, mhocko, brendan.jackman, hannes,
ziy, ljs, liam, rppt, qi.zheng, shakeel.butt, kasong, baohua,
axelrasmussen, yuanchu, weixugc, zhaonanzhe, lipengfei28,
linux-mm, linux-kernel, Bo Zhang
On 19/10/26 8:33 pm, Bo Zhang wrote:
> On 19/10/26 1:42 pm, Dev Jain wrote:
>> I wonder if this function should be left alone?
>>
>> compaction_proactiveness, as I understand is given as a sysfs knob to
>> ensure that the user can control how much power they want to invest into
>> compacting. So suppose the value is 20, and the highest mTHP order is
>> only 2. This gives wmark = 90 * 2 / 9 = 20. So, even if 80% of the memory
>> can serve order-2 allocations, we will still perform compaction for
>> order-2. This seems "extremely proactive" :)
>
> Thanks a lot for looking at this closely, and you are right that the
> scaling factor is the weakest part of this patch. I called it out as an
> open question in the cover letter and I don't have a solid theoretical
> basis for the linear order/COMPACTION_HPAGE_ORDER form.
>
> What pushed me towards scaling the watermark at all was the opposite
> problem on the measurement side: without any scaling, the order-9
> threshold is essentially never reached for a small order, so proactive
> compaction effectively never runs for order-2.
>
> I instrumented fragmentation_score_node() for order-2 on an 8G,
> data=journal kernel-build workload and sampled it at ~100ms. On the
> unpatched kernel the order-2 score looks like this:
>
> order-2 score (unpatched, same workload):
> mean 17.3
> p90 47
> p99 91
> max 100
>
> fraction of time the score exceeds a given threshold:
> > 90 (unscaled, the current order-9 wmark): 1.0%
> > 20 (scaled down to order-2): 27.2%
>
> So with the current (unscaled) watermark, the order-2 score crosses the
> trigger only 1% of the time, which in practice proactive compaction almost
> never fires for order-2.
I get it, so the workload is rapidly allocating mTHP, and kcompactd does not
kick in time, leading to direct compaction (compact_stall) or fallback.
But I think this is a tradeoff with the current design in Linux and has nothing
to do with our mTHP usecase right? Even with PMD sized THP we may have the same
problem.
I think the uncontroversial bit of your patchset is the fact that currently we
migrate large folios just to free up a 2M region. To make forward progress it
will be great if you can find a workload which gets us an improvement without
the threshold changes and we could get those patches merged first.
I am saying that because the reason you keep crossing the 90% threshold is
due to the nature of the workload and that you set 32k mTHP to always. I doubt
on a real system you will cross the threshold this rapidly since mTHP would be
mostly "madvise" and that mTHP-requiring workload wouldn't be the only workload
running.
Given that, one thing that comes to mind is this algorithm - kcompactd wakes up, sees
that the threshold got crossed again, which means it woke up too late. So
it should manipulate the threshold or its wake up time. We need a signal to
say that the mTHP allocation is too abundant and we need background compaction
more frequently.
This algorithm may be in contradiction with the sysctl ... so instead of changing
the threshold, we could lower the wakeup time.
This is similar to how the pcp list changes its threshold if too much allocation
is happening.
>
> That said, your example shows the linear scaling clearly overshoots in
> the other direction: a scaled wmark of ~20 can keep compacting while a
> large fraction of memory is already usable, which is not what the
> proactiveness knob is supposed to express. So I agree the current formula
> is not the right answer.
>
> I'd appreciate your thoughts on the direction here. A couple of options
> I can see:
>
> 1. Leave fragmentation_score_wmark() alone and instead make the score
> itself order-aware / normalized, so that a given proactiveness value
> maps to a comparable amount of work regardless of the target order.
> This keeps the knob's meaning intact.
The challenge is the normalization algorithm, the problem is that there is
nothing we can deduce apart from the fact that
frag_score (order x) <= frag_score (order y) where x <= y.
>
> 2. Keep scaling the watermark but with a floor / non-linear mapping so
> it cannot collapse to a value that triggers when memory is clearly
> sufficient.
>
> I haven't settled on either yet and would rather hear which direction you
> think makes more sense before reworking it.
>
> Also, thanks for the review on patch 4 -- good to know the
> costly/non-costly split seems like a reasonable compromise.
>
> Thanks,
> Bo
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
2026-10-19 8:12 ` Dev Jain
2026-10-19 14:50 ` Xueyuan Chen
2026-10-19 15:03 ` Bo Zhang
@ 2026-10-19 15:47 ` Bo Zhang
2 siblings, 0 replies; 13+ messages in thread
From: Bo Zhang @ 2026-10-19 15:47 UTC (permalink / raw)
To: dev.jain
Cc: akpm, vbabka, david, surenb, mhocko, brendan.jackman, hannes,
ziy, ljs, liam, rppt, qi.zheng, shakeel.butt, kasong, baohua,
axelrasmussen, yuanchu, weixugc, zhaonanzhe, lipengfei28,
linux-mm, linux-kernel
[Resending: my earlier copy does not seem to have reached the list.
Apologies to anyone receiving this twice.]
On 19/10/26 1:42 pm, Dev Jain wrote:
> I wonder if this function should be left alone?
>
> compaction_proactiveness, as I understand is given as a sysfs knob to
> ensure that the user can control how much power they want to invest into
> compacting. So suppose the value is 20, and the highest mTHP order is
> only 2. This gives wmark = 90 * 2 / 9 = 20. So, even if 80% of the memory
> can serve order-2 allocations, we will still perform compaction for
> order-2. This seems "extremely proactive" :)
Thanks a lot for looking at this closely, and you are right that the
scaling factor is the weakest part of this patch. I called it out as an
open question in the cover letter and I don't have a solid theoretical
basis for the linear order/COMPACTION_HPAGE_ORDER form.
What pushed me towards scaling the watermark at all was the opposite
problem on the measurement side: without any scaling, the order-9
threshold is essentially never reached for a small order, so proactive
compaction effectively never runs for order-2.
I instrumented fragmentation_score_node() for order-2 on an 8G,
data=journal kernel-build workload and sampled it at ~100ms. On the
unpatched kernel the order-2 score looks like this:
order-2 score (unpatched, same workload):
mean 17.3
p90 47
p99 91
max 100
fraction of time the score exceeds a given threshold:
> 90 (unscaled, the current order-9 wmark): 1.0%
> 20 (scaled down to order-2): 27.2%
So with the current (unscaled) watermark, the order-2 score crosses the
trigger only 1% of the time, which in practice proactive compaction almost
never fires for order-2.
That said, your example shows the linear scaling clearly overshoots in
the other direction: a scaled wmark of ~20 can keep compacting while a
large fraction of memory is already usable, which is not what the
proactiveness knob is supposed to express. So I agree the current formula
is not the right answer.
I'd appreciate your thoughts on the direction here. A couple of options
I can see:
1. Leave fragmentation_score_wmark() alone and instead make the score
itself order-aware / normalized, so that a given proactiveness value
maps to a comparable amount of work regardless of the target order.
This keeps the knob's meaning intact.
2. Keep scaling the watermark but with a floor / non-linear mapping so
it cannot collapse to a value that triggers when memory is clearly
sufficient.
I haven't settled on either yet and would rather hear which direction you
think makes more sense before reworking it.
Also, thanks for the review on patch 4 -- good to know the
costly/non-costly split seems like a reasonable compromise.
Thanks,
Bo
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH v2 3/4] mm: compaction: skip isolating large folios that already satisfy mTHP
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
2026-10-01 0:14 ` [RFC PATCH v2 1/4] mm: compaction: parameterize fragmentation score by order Bo Zhang
2026-10-01 0:14 ` [RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction Bo Zhang
@ 2026-10-01 0:14 ` Bo Zhang
2026-10-01 0:14 ` [RFC PATCH v2 4/4] mm: compaction: skip unmovable blocks for non-costly proactive mTHP compaction Bo Zhang
` (2 subsequent siblings)
5 siblings, 0 replies; 13+ messages in thread
From: Bo Zhang @ 2026-10-01 0:14 UTC (permalink / raw)
To: akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
When proactive compaction is triggered via compact_memory and mTHP
always-enabled orders are configured, skip isolating folios whose order
is >= the maximum always-enabled mTHP order. These folios already satisfy
mTHP allocation requirements and migrating them is unnecessary overhead.
Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
---
mm/compaction.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/mm/compaction.c b/mm/compaction.c
index 3928a5483efc..0ff454ee5604 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -82,6 +82,15 @@ static inline bool is_via_compact_memory(int order) { return false; }
#define COMPACTION_HPAGE_ORDER (PMD_SHIFT - PAGE_SHIFT)
#endif
+static inline bool mthp_always_enabled(void)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ return !!READ_ONCE(huge_anon_orders_always);
+#else
+ return false;
+#endif
+}
+
static inline int compact_hpage_order(void)
{
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -839,6 +848,12 @@ static bool skip_isolation_on_order(int order, int target_order)
*/
if (!is_via_compact_memory(target_order) && order >= target_order)
return true;
+
+ /* We are compacting for multi-size THP allocation */
+ if (is_via_compact_memory(target_order) && order >= compact_hpage_order() &&
+ mthp_always_enabled())
+ return true;
+
/*
* We limit memory compaction to pageblocks and won't try
* creating free blocks of memory that are larger than that.
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [RFC PATCH v2 4/4] mm: compaction: skip unmovable blocks for non-costly proactive mTHP compaction
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
` (2 preceding siblings ...)
2026-10-01 0:14 ` [RFC PATCH v2 3/4] mm: compaction: skip isolating large folios that already satisfy mTHP Bo Zhang
@ 2026-10-01 0:14 ` Bo Zhang
2026-10-19 9:43 ` Dev Jain
2026-10-19 15:50 ` [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Xueyuan Chen
2026-10-20 14:52 ` Vlastimil Babka (SUSE)
5 siblings, 1 reply; 13+ messages in thread
From: Bo Zhang @ 2026-10-01 0:14 UTC (permalink / raw)
To: akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
Proactive compaction scans all pageblocks including unmovable/reclaimable
ones. For non-costly mTHP orders (<= PAGE_ALLOC_COSTLY_ORDER), those blocks
are dominated by non-migratable kernel allocations (slab, page tables) and
scanning them wastes cycles: a small order is easily satisfied from movable
blocks alone, so there is no need to scavenge the few migratable fallback
pages inside unmovable blocks.
Costly orders keep scanning all blocks: they are hard to form and benefit
from any migratable page available, including allocator fallbacks inside
unmovable blocks.
Restrict non-costly proactive compaction to movable/CMA blocks.
Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
---
mm/compaction.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mm/compaction.c b/mm/compaction.c
index 0ff454ee5604..deddf931d0f2 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1404,10 +1404,19 @@ static bool suitable_migration_source(struct compact_control *cc,
struct page *page)
{
int block_mt;
+ unsigned int order = compact_hpage_order();
+ bool costly = order > PAGE_ALLOC_COSTLY_ORDER;
if (pageblock_skip_persistent(page))
return false;
+ if (is_via_compact_memory(cc->order) && !costly) {
+ block_mt = get_pageblock_migratetype(page);
+ if (block_mt == MIGRATE_MOVABLE || is_migrate_cma(block_mt))
+ return true;
+ return false;
+ }
+
/*
* Background compaction produces blocks for the zone at
* large, with no particular allocation context. Allow all
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 4/4] mm: compaction: skip unmovable blocks for non-costly proactive mTHP compaction
2026-10-01 0:14 ` [RFC PATCH v2 4/4] mm: compaction: skip unmovable blocks for non-costly proactive mTHP compaction Bo Zhang
@ 2026-10-19 9:43 ` Dev Jain
0 siblings, 0 replies; 13+ messages in thread
From: Dev Jain @ 2026-10-19 9:43 UTC (permalink / raw)
To: Bo Zhang, akpm, vbabka, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
On 01/10/26 5:44 am, Bo Zhang wrote:
> Proactive compaction scans all pageblocks including unmovable/reclaimable
> ones. For non-costly mTHP orders (<= PAGE_ALLOC_COSTLY_ORDER), those blocks
> are dominated by non-migratable kernel allocations (slab, page tables) and
> scanning them wastes cycles: a small order is easily satisfied from movable
> blocks alone, so there is no need to scavenge the few migratable fallback
> pages inside unmovable blocks.
>
> Costly orders keep scanning all blocks: they are hard to form and benefit
> from any migratable page available, including allocator fallbacks inside
> unmovable blocks.
I think this is a reasonable compromise for now.
>
> Restrict non-costly proactive compaction to movable/CMA blocks.
>
> Signed-off-by: Bo Zhang <zhangbo56@xiaomi.com>
> ---
> mm/compaction.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/mm/compaction.c b/mm/compaction.c
> index 0ff454ee5604..deddf931d0f2 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -1404,10 +1404,19 @@ static bool suitable_migration_source(struct compact_control *cc,
> struct page *page)
> {
> int block_mt;
> + unsigned int order = compact_hpage_order();
> + bool costly = order > PAGE_ALLOC_COSTLY_ORDER;
>
> if (pageblock_skip_persistent(page))
> return false;
>
> + if (is_via_compact_memory(cc->order) && !costly) {
> + block_mt = get_pageblock_migratetype(page);
> + if (block_mt == MIGRATE_MOVABLE || is_migrate_cma(block_mt))
> + return true;
> + return false;
> + }
> +
> /*
> * Background compaction produces blocks for the zone at
> * large, with no particular allocation context. Allow al
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
` (3 preceding siblings ...)
2026-10-01 0:14 ` [RFC PATCH v2 4/4] mm: compaction: skip unmovable blocks for non-costly proactive mTHP compaction Bo Zhang
@ 2026-10-19 15:50 ` Xueyuan Chen
2026-10-20 14:52 ` Vlastimil Babka (SUSE)
5 siblings, 0 replies; 13+ messages in thread
From: Xueyuan Chen @ 2026-10-19 15:50 UTC (permalink / raw)
To: zhangbo0325
Cc: akpm, vbabka, david, surenb, mhocko, brendan.jackman, hannes,
ziy, ljs, liam, rppt, qi.zheng, shakeel.butt, kasong, baohua,
axelrasmussen, yuanchu, weixugc, zhaonanzhe, lipengfei28,
linux-mm, linux-kernel, zhangbo56, Xueyuan Chen
On Thu, Oct 01, 2026 at 08:14:08AM +0800, Bo Zhang wrote:
>Hi all,
>
>This series improves memory compaction to better serve mTHP (multi-size
>THP) allocations, particularly for small orders like order-2 (16KB).
>The changes focus on the proactive (kcompactd) compaction path.
>
>Problem:
>
>The current proactive compaction targets COMPACTION_HPAGE_ORDER (order-9,
>2MB), which is unfriendly to mTHP in two ways:
>
>1. It migrates folios that already satisfy mTHP allocation needs. For
> example, an order-2 folio is a valid mTHP page, yet compaction still
> moves it around trying to form order-9 blocks. This is unnecessary
> work and wastes energy.
>
>2. Compaction designed for 2MB huge pages is too heavyweight for mTHP.
> mTHP allocations are frequent and only require small contiguous blocks
> (e.g., 4 pages for order-2). A lighter-weight, mTHP-aware compaction
> strategy is needed to reduce overhead and power consumption.
>
>Approach:
>
>This series makes four changes:
>
>1. Generalize the fragmentation score functions to accept an order
> parameter. This is a pure refactor with no functional change; all
> callers still pass COMPACTION_HPAGE_ORDER.
>
>2. Use the highest always-enabled mTHP order as the proactive compaction
> target. Because a fragmentation score for a small order is naturally
> much lower than for order-9 under the same fragmentation state, the
> proactive watermark is scaled down in proportion to the target order;
> otherwise a small order would almost never reach the trigger threshold.
>
>3. During proactive compaction (compact_memory), skip isolating folios
> that already satisfy mTHP requirements, avoiding unnecessary migration
> overhead.
>
>4. For non-costly mTHP orders, restrict proactive compaction to movable
> (and CMA) pageblocks. Unmovable/reclaimable blocks are dominated by
> non-migratable kernel allocations. scanning them wastes cycles because
> a small order can be satisfied from movable blocks alone. Costly orders
> keep scanning all blocks, since they are harder to form and benefit
> from any migratable page available.
>
>Test setup:
>
>x86 host, arm64 cross-build (defconfig + CONFIG_DEBUG_INFO=y,
>CONFIG_DEBUG_INFO_DWARF5=y), booted with mem=4G. order-3 (32KB) mTHP is
>set to "always"; ext4 root mounted data=journal. The kernel build
>naturally fragments order-3 free memory during the run.
>
>Runtime (two defrag modes were tested, see Results):
> echo always > .../hugepages-32kB/enabled
> echo madvise > .../transparent_hugepage/defrag # or: always
> echo 20 > /proc/sys/vm/compaction_proactiveness
>
>A background loop keeps proactiveness poked every 100ms so kcompactd
>re-evaluates promptly (its default 500ms interval is too coarse to catch
>the transient order-3 fragmentation peaks under this workload):
>
> while true; do
> echo 20 > /proc/sys/vm/compaction_proactiveness
> sleep 0.1
> done
>
>Workload: make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- vmlinux -j28
>5 rounds per configuration; each round: make clean + drop_caches, then
>counter deltas around the build. The baseline is the unmodified kernel.
>
>Results (5-round means). anon_fault_alloc is within 1% between kernels,
>so the fallback numbers are directly comparable.
>
>defrag=madvise:
> w/o patch w/ patch change
> -------------------------- ----------- ----------- --------
> anon_fault_alloc 14,307,597 14,401,699 +1%
> anon_fault_fallback 97,701 40,975 -58%
> fallback ratio 0.68% 0.28%
> compact_isolated 8,479,773 1,458,949 -83%
> compact_migrate_scanned 78,198,828 22,900,359 -71%
> kcompactd cpu (s) 43 7 -84%
> sys (kernel build) 6m34s 6m34s ~0%
>
>defrag=always:
> w/o patch w/ patch change
> -------------------------- ----------- ----------- --------
> anon_fault_alloc 14,370,984 14,404,234 ~0%
> anon_fault_fallback 619 823
> compact_stall 979 585 -40%
> compact_isolated 6,390,940 2,431,800 -62%
> compact_migrate_scanned 86,171,095 46,339,911 -46%
> kcompactd cpu (s) 36 13 -62%
> sys (kernel build) 6m34s 6m27s -1.8%
>
>1. With defrag=madvise, the patch cuts mTHP fallback by 58% (ratio
> 0.68% -> 0.28%).
>
>2. With defrag=always, direct compaction already keeps fallback near
> zero, and the patch instead cuts direct compaction stalls by 40%.
>
>In both cases the compaction is done far more cheaply (kcompactd CPU
>-62..84%, compact_isolated/scanned -46..83%).
Hi Bo,
With proactive compaction enabled, have you measured the change in power
consumption on Android devices after applying this patch series?
>
>Open questions:
>
>1. In skip_isolation_on_order() and elsewhere, the target order is read
> from huge_anon_orders_always directly, since during proactive
> compaction cc->order is -1 (via compact_memory) and there is no clean
> way to plumb the mTHP order down. This variable can change under
> userspace at any time, making the semantics fragile. Ideas on how to
> pass the target order through the proactive path cleanly are welcome.
>
>2. The proactive watermark is scaled linearly by the target order
> (wmark * order / COMPACTION_HPAGE_ORDER). This is empirical; a more
> principled cross-order normalization of the fragmentation score would
> be welcome.
>
>Changes since v1
>================
>
>The series is now scoped to the proactive compaction path only. Two
>patches from v1 were dropped, and two new mechanisms were added:
>
>- Dropped v1 patch 3 ("don't skip proactive compaction for non-costly
> mTHP", i.e. running proactive compaction concurrently with kswapd).
> Follow-up testing showed it lowered fallback mainly by driving extra
> anonymous reclaim/swap rather than by better compaction; keeping the
> original kswapd back-off avoids trading workingset for mTHP fallback.
>
>- Dropped v1 patch 4 (mTHP-aware zone_effective_free_pages() watermark):
> it added reclaim pressure without a clear net benefit in this scope.
>
>- Split the former patch 1 into a pure refactor (parameterize the
> fragmentation score by order) plus the mTHP-targeting change, so the
> mechanical and behavioural parts can be reviewed independently.
>
>- Added the proactive watermark scaling by target order, so a small mTHP
> order can actually reach the trigger threshold.
>
>- Added patch 4 (skip unmovable blocks for non-costly proactive mTHP
> compaction). Without it, proactive compaction wastes most of its
> scanning on unmovable blocks full of kernel allocations; with it,
> kcompactd's CPU and the scanned/isolated counters drop by an order of
> magnitude while fallback still improves.
>
>- compact_hpage_order() uses __fls() (highest always-enabled mTHP order)
> guarded by #ifdef CONFIG_TRANSPARENT_HUGEPAGE (m68k allmodconfig build
> fix from the kernel test robot).
>
>- Refreshed test data on an mem=4G, order-3, data=journal kernel-build
> workload; see Results above.
>
>Bo Zhang (4):
> mm: compaction: parameterize fragmentation score by order
> mm: compaction: target mTHP order for proactive compaction
> mm: compaction: skip isolating large folios that already satisfy mTHP
> mm: compaction: skip unmovable blocks for non-costly proactive mTHP
> compaction
>
> mm/compaction.c | 85 +++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 68 insertions(+), 17 deletions(-)
>
>--
>2.34.1
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction
2026-10-01 0:14 [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Bo Zhang
` (4 preceding siblings ...)
2026-10-19 15:50 ` [RFC PATCH v2 0/4] mm: compaction: mTHP-friendly memory compaction Xueyuan Chen
@ 2026-10-20 14:52 ` Vlastimil Babka (SUSE)
5 siblings, 0 replies; 13+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-10-20 14:52 UTC (permalink / raw)
To: Bo Zhang, akpm, david
Cc: surenb, mhocko, brendan.jackman, hannes, ziy, ljs, liam, rppt,
qi.zheng, shakeel.butt, kasong, baohua, axelrasmussen, yuanchu,
weixugc, zhaonanzhe, lipengfei28, linux-mm, linux-kernel,
Bo Zhang
On 10/1/26 02:14, Bo Zhang wrote:
> Open questions:
>
> 1. In skip_isolation_on_order() and elsewhere, the target order is read
> from huge_anon_orders_always directly, since during proactive
> compaction cc->order is -1 (via compact_memory) and there is no clean
> way to plumb the mTHP order down.
Isn't using struct compact_control clean enough? There's already many
fields like
bool direct_compaction; /* False from kcompactd or /proc/... */
bool proactive_compaction; /* kcompactd proactive compaction */
Who says is_via_compact_memory() cannot be refactored into something using
these kinds of fields and not 'order' being -1, which could be then used as
the target order.
> This variable can change under
> userspace at any time, making the semantics fragile. Ideas on how to
> pass the target order through the proactive path cleanly are welcome.
>
^ permalink raw reply [flat|nested] 13+ messages in thread