Commit 782fd304 authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds

mm: avoid waking kswapd for THP allocations when compaction is deferred or contended

With "mm: vmscan: scale number of pages reclaimed by reclaim/compaction
based on failures" reverted, Zdenek Kabelac reported the following

  Hmm,  so it's just took longer to hit the problem and observe
  kswapd0 spinning on my CPU again - it's not as endless like before -
  but still it easily eats minutes - it helps to turn off  Firefox
  or TB  (memory hungry apps) so kswapd0 stops soon - and restart
  those apps again.  (And I still have like >1GB of cached memory)

  kswapd0         R  running task        0    30      2 0x00000000
  Call Trace:
    preempt_schedule+0x42/0x60
    _raw_spin_unlock+0x55/0x60
    put_super+0x31/0x40
    drop_super+0x22/0x30
    prune_super+0x149/0x1b0
    shrink_slab+0xba/0x510

The sysrq+m indicates the system has no swap so it'll never reclaim
anonymous pages as part of reclaim/compaction.  That is one part of the
problem but not the root cause as file-backed pages could also be
reclaimed.

The likely underlying problem is that kswapd is woken up or kept awake
for each THP allocation request in the page allocator slow path.

If compaction fails for the requesting process then compaction will be
deferred for a time and direct reclaim is avoided.  However, if there
are a storm of THP requests that are simply rejected, it will still be
the the case that kswapd is awake for a prolonged period of time as
pgdat->kswapd_max_order is updated each time.  This is noticed by the
main kswapd() loop and it will not call kswapd_try_to_sleep().  Instead
it will loopp, shrinking a small number of pages and calling
shrink_slab() on each iteration.

This patch defers when kswapd gets woken up for THP allocations.  For
!THP allocations, kswapd is always woken up.  For THP allocations,
kswapd is woken up iff the process is willing to enter into direct
reclaim/compaction.

[akpm@linux-foundation.org: fix typo in comment]
Signed-off-by: default avatarMel Gorman <mgorman@suse.de>
Cc: Zdenek Kabelac <zkabelac@redhat.com>
Cc: Seth Jennings <sjenning@linux.vnet.ibm.com>
Cc: Jiri Slaby <jirislaby@gmail.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Robert Jennings <rcj@linux.vnet.ibm.com>
Cc: Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Cc: Glauber Costa <glommer@gmail.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a5091539
...@@ -2378,6 +2378,15 @@ bool gfp_pfmemalloc_allowed(gfp_t gfp_mask) ...@@ -2378,6 +2378,15 @@ bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
return !!(gfp_to_alloc_flags(gfp_mask) & ALLOC_NO_WATERMARKS); return !!(gfp_to_alloc_flags(gfp_mask) & ALLOC_NO_WATERMARKS);
} }
/* Returns true if the allocation is likely for THP */
static bool is_thp_alloc(gfp_t gfp_mask, unsigned int order)
{
if (order == pageblock_order &&
(gfp_mask & (__GFP_MOVABLE|__GFP_REPEAT)) == __GFP_MOVABLE)
return true;
return false;
}
static inline struct page * static inline struct page *
__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
struct zonelist *zonelist, enum zone_type high_zoneidx, struct zonelist *zonelist, enum zone_type high_zoneidx,
...@@ -2416,6 +2425,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, ...@@ -2416,6 +2425,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
goto nopage; goto nopage;
restart: restart:
/* The decision whether to wake kswapd for THP is made later */
if (!is_thp_alloc(gfp_mask, order))
wake_all_kswapd(order, zonelist, high_zoneidx, wake_all_kswapd(order, zonelist, high_zoneidx,
zone_idx(preferred_zone)); zone_idx(preferred_zone));
...@@ -2487,16 +2498,22 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, ...@@ -2487,16 +2498,22 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
goto got_pg; goto got_pg;
sync_migration = true; sync_migration = true;
if (is_thp_alloc(gfp_mask, order)) {
/* /*
* If compaction is deferred for high-order allocations, it is because * If compaction is deferred for high-order allocations, it is
* sync compaction recently failed. In this is the case and the caller * because sync compaction recently failed. If this is the case
* requested a movable allocation that does not heavily disrupt the * and the caller requested a movable allocation that does not
* system then fail the allocation instead of entering direct reclaim. * heavily disrupt the system then fail the allocation instead
* of entering direct reclaim.
*/ */
if ((deferred_compaction || contended_compaction) && if (deferred_compaction || contended_compaction)
(gfp_mask & (__GFP_MOVABLE|__GFP_REPEAT)) == __GFP_MOVABLE)
goto nopage; goto nopage;
/* If process is willing to reclaim/compact then wake kswapd */
wake_all_kswapd(order, zonelist, high_zoneidx,
zone_idx(preferred_zone));
}
/* Try direct reclaim and then allocating */ /* Try direct reclaim and then allocating */
page = __alloc_pages_direct_reclaim(gfp_mask, order, page = __alloc_pages_direct_reclaim(gfp_mask, order,
zonelist, high_zoneidx, zonelist, high_zoneidx,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment