[RFC PATCH v2 2/4] mm: compaction: target mTHP order for proactive compaction
From: Bo Zhang
Date: Wed Sep 30 2026 - 20:15:09 EST
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@xxxxxxxxxx>
---
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