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 --- 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 #include #include +#include #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