* [PATCH 1/5] mm: compaction: remove compaction result helpers
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
@ 2023-05-19 12:39 ` Johannes Weiner
2023-05-29 9:58 ` Vlastimil Babka
2023-05-19 12:39 ` [PATCH 2/5] mm: compaction: simplify should_compact_retry() Johannes Weiner
` (4 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-19 12:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
The compaction result helpers encode quirks that are specific to the
allocator's retry logic. E.g. COMPACT_SUCCESS and COMPACT_COMPLETE
actually represent failures that should be retried upon, and so on. I
frequently found myself pulling up the helper implementation in order
to understand and work on the retry logic. They're not quite clean
abstractions; rather they split the retry logic into two locations.
Remove the helpers and inline the checks. Then comment on the result
interpretations directly where the decision making happens.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/compaction.h | 92 ----------------------------------
include/trace/events/mmflags.h | 4 +-
mm/page_alloc.c | 30 ++++++-----
3 files changed, 19 insertions(+), 107 deletions(-)
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index a6e512cfb670..1f0328a2ba48 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -95,78 +95,6 @@ extern enum compact_result compaction_suitable(struct zone *zone, int order,
extern void compaction_defer_reset(struct zone *zone, int order,
bool alloc_success);
-/* Compaction has made some progress and retrying makes sense */
-static inline bool compaction_made_progress(enum compact_result result)
-{
- /*
- * Even though this might sound confusing this in fact tells us
- * that the compaction successfully isolated and migrated some
- * pageblocks.
- */
- if (result == COMPACT_SUCCESS)
- return true;
-
- return false;
-}
-
-/* Compaction has failed and it doesn't make much sense to keep retrying. */
-static inline bool compaction_failed(enum compact_result result)
-{
- /* All zones were scanned completely and still not result. */
- if (result == COMPACT_COMPLETE)
- return true;
-
- return false;
-}
-
-/* Compaction needs reclaim to be performed first, so it can continue. */
-static inline bool compaction_needs_reclaim(enum compact_result result)
-{
- /*
- * Compaction backed off due to watermark checks for order-0
- * so the regular reclaim has to try harder and reclaim something.
- */
- if (result == COMPACT_SKIPPED)
- return true;
-
- return false;
-}
-
-/*
- * Compaction has backed off for some reason after doing some work or none
- * at all. It might be throttling or lock contention. Retrying might be still
- * worthwhile, but with a higher priority if allowed.
- */
-static inline bool compaction_withdrawn(enum compact_result result)
-{
- /*
- * If compaction is deferred for high-order allocations, it is
- * because sync compaction recently failed. If this is the case
- * and the caller requested a THP allocation, we do not want
- * to heavily disrupt the system, so we fail the allocation
- * instead of entering direct reclaim.
- */
- if (result == COMPACT_DEFERRED)
- return true;
-
- /*
- * If compaction in async mode encounters contention or blocks higher
- * priority task we back off early rather than cause stalls.
- */
- if (result == COMPACT_CONTENDED)
- return true;
-
- /*
- * Page scanners have met but we haven't scanned full zones so this
- * is a back off in fact.
- */
- if (result == COMPACT_PARTIAL_SKIPPED)
- return true;
-
- return false;
-}
-
-
bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
int alloc_flags);
@@ -185,26 +113,6 @@ static inline enum compact_result compaction_suitable(struct zone *zone, int ord
return COMPACT_SKIPPED;
}
-static inline bool compaction_made_progress(enum compact_result result)
-{
- return false;
-}
-
-static inline bool compaction_failed(enum compact_result result)
-{
- return false;
-}
-
-static inline bool compaction_needs_reclaim(enum compact_result result)
-{
- return false;
-}
-
-static inline bool compaction_withdrawn(enum compact_result result)
-{
- return true;
-}
-
static inline void kcompactd_run(int nid)
{
}
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index b63e7c0fbbe5..1478b9dd05fa 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -223,8 +223,8 @@ IF_HAVE_VM_SOFTDIRTY(VM_SOFTDIRTY, "softdirty" ) \
#define compact_result_to_feedback(result) \
({ \
enum compact_result __result = result; \
- (compaction_failed(__result)) ? COMPACTION_FAILED : \
- (compaction_withdrawn(__result)) ? COMPACTION_WITHDRAWN : COMPACTION_PROGRESS; \
+ (__result == COMPACT_COMPLETE) ? COMPACTION_FAILED : \
+ (__result == COMPACT_SUCCESS) ? COMPACTION_PROGRESS : COMPACTION_WITHDRAWN; \
})
#define COMPACTION_FEEDBACK \
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 47421bedc12b..5a84a0bebc37 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3768,35 +3768,39 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
if (fatal_signal_pending(current))
return false;
- if (compaction_made_progress(compact_result))
+ /*
+ * Compaction managed to coalesce some page blocks, but the
+ * allocation failed presumably due to a race. Retry some.
+ */
+ if (compact_result == COMPACT_SUCCESS)
(*compaction_retries)++;
/*
- * compaction considers all the zone as desperately out of memory
- * so it doesn't really make much sense to retry except when the
+ * All zones were scanned completely and still no result. It
+ * doesn't really make much sense to retry except when the
* failure could be caused by insufficient priority
*/
- if (compaction_failed(compact_result))
+ if (compact_result == COMPACT_COMPLETE)
goto check_priority;
/*
- * compaction was skipped because there are not enough order-0 pages
- * to work with, so we retry only if it looks like reclaim can help.
+ * Compaction was skipped due to a lack of free order-0
+ * migration targets. Continue if reclaim can help.
*/
- if (compaction_needs_reclaim(compact_result)) {
+ if (compact_result == COMPACT_SKIPPED) {
ret = compaction_zonelist_suitable(ac, order, alloc_flags);
goto out;
}
/*
- * make sure the compaction wasn't deferred or didn't bail out early
- * due to locks contention before we declare that we should give up.
- * But the next retry should use a higher priority if allowed, so
- * we don't just keep bailing out endlessly.
+ * If compaction backed due to being deferred, due to
+ * contended locks in async mode, or due to scanners meeting
+ * after a partial scan, retry with increased priority.
*/
- if (compaction_withdrawn(compact_result)) {
+ if (compact_result == COMPACT_DEFERRED ||
+ compact_result == COMPACT_CONTENDED ||
+ compact_result == COMPACT_PARTIAL_SKIPPED)
goto check_priority;
- }
/*
* !costly requests are much more important than __GFP_RETRY_MAYFAIL
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 1/5] mm: compaction: remove compaction result helpers
2023-05-19 12:39 ` [PATCH 1/5] mm: compaction: remove compaction result helpers Johannes Weiner
@ 2023-05-29 9:58 ` Vlastimil Babka
0 siblings, 0 replies; 17+ messages in thread
From: Vlastimil Babka @ 2023-05-29 9:58 UTC (permalink / raw)
To: Johannes Weiner, Andrew Morton
Cc: Mel Gorman, Michal Hocko, linux-mm, linux-kernel, kernel-team
On 5/19/23 14:39, Johannes Weiner wrote:
> The compaction result helpers encode quirks that are specific to the
> allocator's retry logic. E.g. COMPACT_SUCCESS and COMPACT_COMPLETE
> actually represent failures that should be retried upon, and so on. I
> frequently found myself pulling up the helper implementation in order
> to understand and work on the retry logic. They're not quite clean
> abstractions; rather they split the retry logic into two locations.
>
> Remove the helpers and inline the checks. Then comment on the result
> interpretations directly where the decision making happens.
>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Since the usage of helpers never proliferated outside of
should_compact_retry() with the exception of tracepoint, I guess it makes
sense to remove them.
Acked-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> include/linux/compaction.h | 92 ----------------------------------
> include/trace/events/mmflags.h | 4 +-
> mm/page_alloc.c | 30 ++++++-----
> 3 files changed, 19 insertions(+), 107 deletions(-)
>
> diff --git a/include/linux/compaction.h b/include/linux/compaction.h
> index a6e512cfb670..1f0328a2ba48 100644
> --- a/include/linux/compaction.h
> +++ b/include/linux/compaction.h
> @@ -95,78 +95,6 @@ extern enum compact_result compaction_suitable(struct zone *zone, int order,
> extern void compaction_defer_reset(struct zone *zone, int order,
> bool alloc_success);
>
> -/* Compaction has made some progress and retrying makes sense */
> -static inline bool compaction_made_progress(enum compact_result result)
> -{
> - /*
> - * Even though this might sound confusing this in fact tells us
> - * that the compaction successfully isolated and migrated some
> - * pageblocks.
> - */
> - if (result == COMPACT_SUCCESS)
> - return true;
> -
> - return false;
> -}
> -
> -/* Compaction has failed and it doesn't make much sense to keep retrying. */
> -static inline bool compaction_failed(enum compact_result result)
> -{
> - /* All zones were scanned completely and still not result. */
> - if (result == COMPACT_COMPLETE)
> - return true;
> -
> - return false;
> -}
> -
> -/* Compaction needs reclaim to be performed first, so it can continue. */
> -static inline bool compaction_needs_reclaim(enum compact_result result)
> -{
> - /*
> - * Compaction backed off due to watermark checks for order-0
> - * so the regular reclaim has to try harder and reclaim something.
> - */
> - if (result == COMPACT_SKIPPED)
> - return true;
> -
> - return false;
> -}
> -
> -/*
> - * Compaction has backed off for some reason after doing some work or none
> - * at all. It might be throttling or lock contention. Retrying might be still
> - * worthwhile, but with a higher priority if allowed.
> - */
> -static inline bool compaction_withdrawn(enum compact_result result)
> -{
> - /*
> - * If compaction is deferred for high-order allocations, it is
> - * because sync compaction recently failed. If this is the case
> - * and the caller requested a THP allocation, we do not want
> - * to heavily disrupt the system, so we fail the allocation
> - * instead of entering direct reclaim.
> - */
> - if (result == COMPACT_DEFERRED)
> - return true;
> -
> - /*
> - * If compaction in async mode encounters contention or blocks higher
> - * priority task we back off early rather than cause stalls.
> - */
> - if (result == COMPACT_CONTENDED)
> - return true;
> -
> - /*
> - * Page scanners have met but we haven't scanned full zones so this
> - * is a back off in fact.
> - */
> - if (result == COMPACT_PARTIAL_SKIPPED)
> - return true;
> -
> - return false;
> -}
> -
> -
> bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
> int alloc_flags);
>
> @@ -185,26 +113,6 @@ static inline enum compact_result compaction_suitable(struct zone *zone, int ord
> return COMPACT_SKIPPED;
> }
>
> -static inline bool compaction_made_progress(enum compact_result result)
> -{
> - return false;
> -}
> -
> -static inline bool compaction_failed(enum compact_result result)
> -{
> - return false;
> -}
> -
> -static inline bool compaction_needs_reclaim(enum compact_result result)
> -{
> - return false;
> -}
> -
> -static inline bool compaction_withdrawn(enum compact_result result)
> -{
> - return true;
> -}
> -
> static inline void kcompactd_run(int nid)
> {
> }
> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
> index b63e7c0fbbe5..1478b9dd05fa 100644
> --- a/include/trace/events/mmflags.h
> +++ b/include/trace/events/mmflags.h
> @@ -223,8 +223,8 @@ IF_HAVE_VM_SOFTDIRTY(VM_SOFTDIRTY, "softdirty" ) \
> #define compact_result_to_feedback(result) \
> ({ \
> enum compact_result __result = result; \
> - (compaction_failed(__result)) ? COMPACTION_FAILED : \
> - (compaction_withdrawn(__result)) ? COMPACTION_WITHDRAWN : COMPACTION_PROGRESS; \
> + (__result == COMPACT_COMPLETE) ? COMPACTION_FAILED : \
> + (__result == COMPACT_SUCCESS) ? COMPACTION_PROGRESS : COMPACTION_WITHDRAWN; \
> })
>
> #define COMPACTION_FEEDBACK \
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 47421bedc12b..5a84a0bebc37 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3768,35 +3768,39 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> if (fatal_signal_pending(current))
> return false;
>
> - if (compaction_made_progress(compact_result))
> + /*
> + * Compaction managed to coalesce some page blocks, but the
> + * allocation failed presumably due to a race. Retry some.
> + */
> + if (compact_result == COMPACT_SUCCESS)
> (*compaction_retries)++;
>
> /*
> - * compaction considers all the zone as desperately out of memory
> - * so it doesn't really make much sense to retry except when the
> + * All zones were scanned completely and still no result. It
> + * doesn't really make much sense to retry except when the
> * failure could be caused by insufficient priority
> */
> - if (compaction_failed(compact_result))
> + if (compact_result == COMPACT_COMPLETE)
> goto check_priority;
>
> /*
> - * compaction was skipped because there are not enough order-0 pages
> - * to work with, so we retry only if it looks like reclaim can help.
> + * Compaction was skipped due to a lack of free order-0
> + * migration targets. Continue if reclaim can help.
> */
> - if (compaction_needs_reclaim(compact_result)) {
> + if (compact_result == COMPACT_SKIPPED) {
> ret = compaction_zonelist_suitable(ac, order, alloc_flags);
> goto out;
> }
>
> /*
> - * make sure the compaction wasn't deferred or didn't bail out early
> - * due to locks contention before we declare that we should give up.
> - * But the next retry should use a higher priority if allowed, so
> - * we don't just keep bailing out endlessly.
> + * If compaction backed due to being deferred, due to
> + * contended locks in async mode, or due to scanners meeting
> + * after a partial scan, retry with increased priority.
> */
> - if (compaction_withdrawn(compact_result)) {
> + if (compact_result == COMPACT_DEFERRED ||
> + compact_result == COMPACT_CONTENDED ||
> + compact_result == COMPACT_PARTIAL_SKIPPED)
> goto check_priority;
> - }
>
> /*
> * !costly requests are much more important than __GFP_RETRY_MAYFAIL
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/5] mm: compaction: simplify should_compact_retry()
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
2023-05-19 12:39 ` [PATCH 1/5] mm: compaction: remove compaction result helpers Johannes Weiner
@ 2023-05-19 12:39 ` Johannes Weiner
2023-05-29 13:03 ` Vlastimil Babka
2023-05-19 12:39 ` [PATCH 3/5] mm: compaction: refactor __compaction_suitable() Johannes Weiner
` (3 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-19 12:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
The different branches for retry are unnecessarily complicated. There
are really only three outcomes: progress (retry n times), skipped
(retry if reclaim can help), failed (retry with higher priority).
Rearrange the branches and the retry counter to make it simpler.
v2:
- fix trace point build (Mel)
- fix max_retries logic for costly allocs (Huang)
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/page_alloc.c | 53 +++++++++++++++----------------------------------
1 file changed, 16 insertions(+), 37 deletions(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 5a84a0bebc37..72660e924b95 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3772,16 +3772,22 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
* Compaction managed to coalesce some page blocks, but the
* allocation failed presumably due to a race. Retry some.
*/
- if (compact_result == COMPACT_SUCCESS)
- (*compaction_retries)++;
+ if (compact_result == COMPACT_SUCCESS) {
+ /*
+ * !costly requests are much more important than
+ * __GFP_RETRY_MAYFAIL costly ones because they are de
+ * facto nofail and invoke OOM killer to move on while
+ * costly can fail and users are ready to cope with
+ * that. 1/4 retries is rather arbitrary but we would
+ * need much more detailed feedback from compaction to
+ * make a better decision.
+ */
+ if (order > PAGE_ALLOC_COSTLY_ORDER)
+ max_retries /= 4;
- /*
- * All zones were scanned completely and still no result. It
- * doesn't really make much sense to retry except when the
- * failure could be caused by insufficient priority
- */
- if (compact_result == COMPACT_COMPLETE)
- goto check_priority;
+ ret = ++(*compaction_retries) <= max_retries;
+ goto out;
+ }
/*
* Compaction was skipped due to a lack of free order-0
@@ -3793,35 +3799,8 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
}
/*
- * If compaction backed due to being deferred, due to
- * contended locks in async mode, or due to scanners meeting
- * after a partial scan, retry with increased priority.
- */
- if (compact_result == COMPACT_DEFERRED ||
- compact_result == COMPACT_CONTENDED ||
- compact_result == COMPACT_PARTIAL_SKIPPED)
- goto check_priority;
-
- /*
- * !costly requests are much more important than __GFP_RETRY_MAYFAIL
- * costly ones because they are de facto nofail and invoke OOM
- * killer to move on while costly can fail and users are ready
- * to cope with that. 1/4 retries is rather arbitrary but we
- * would need much more detailed feedback from compaction to
- * make a better decision.
- */
- if (order > PAGE_ALLOC_COSTLY_ORDER)
- max_retries /= 4;
- if (*compaction_retries <= max_retries) {
- ret = true;
- goto out;
- }
-
- /*
- * Make sure there are attempts at the highest priority if we exhausted
- * all retries or failed at the lower priorities.
+ * Compaction failed. Retry with increasing priority.
*/
-check_priority:
min_priority = (order > PAGE_ALLOC_COSTLY_ORDER) ?
MIN_COMPACT_COSTLY_PRIORITY : MIN_COMPACT_PRIORITY;
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 2/5] mm: compaction: simplify should_compact_retry()
2023-05-19 12:39 ` [PATCH 2/5] mm: compaction: simplify should_compact_retry() Johannes Weiner
@ 2023-05-29 13:03 ` Vlastimil Babka
2023-05-29 16:38 ` Johannes Weiner
0 siblings, 1 reply; 17+ messages in thread
From: Vlastimil Babka @ 2023-05-29 13:03 UTC (permalink / raw)
To: Johannes Weiner, Andrew Morton
Cc: Mel Gorman, Michal Hocko, linux-mm, linux-kernel, kernel-team
On 5/19/23 14:39, Johannes Weiner wrote:
> The different branches for retry are unnecessarily complicated. There
> are really only three outcomes: progress (retry n times), skipped
> (retry if reclaim can help), failed (retry with higher priority).
>
> Rearrange the branches and the retry counter to make it simpler.
>
> v2:
> - fix trace point build (Mel)
> - fix max_retries logic for costly allocs (Huang)
>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
> ---
> mm/page_alloc.c | 53 +++++++++++++++----------------------------------
> 1 file changed, 16 insertions(+), 37 deletions(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 5a84a0bebc37..72660e924b95 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3772,16 +3772,22 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> * Compaction managed to coalesce some page blocks, but the
> * allocation failed presumably due to a race. Retry some.
> */
> - if (compact_result == COMPACT_SUCCESS)
> - (*compaction_retries)++;
> + if (compact_result == COMPACT_SUCCESS) {
> + /*
> + * !costly requests are much more important than
> + * __GFP_RETRY_MAYFAIL costly ones because they are de
> + * facto nofail and invoke OOM killer to move on while
> + * costly can fail and users are ready to cope with
> + * that. 1/4 retries is rather arbitrary but we would
> + * need much more detailed feedback from compaction to
> + * make a better decision.
> + */
> + if (order > PAGE_ALLOC_COSTLY_ORDER)
> + max_retries /= 4;
>
> - /*
> - * All zones were scanned completely and still no result. It
> - * doesn't really make much sense to retry except when the
> - * failure could be caused by insufficient priority
> - */
> - if (compact_result == COMPACT_COMPLETE)
> - goto check_priority;
> + ret = ++(*compaction_retries) <= max_retries;
> + goto out;
I think you simplified this part too much, so now once it runs out of
retries, it will return false, while previously it would increase the priority.
> + }
>
> /*
> * Compaction was skipped due to a lack of free order-0
> @@ -3793,35 +3799,8 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> }
>
> /*
> - * If compaction backed due to being deferred, due to
> - * contended locks in async mode, or due to scanners meeting
> - * after a partial scan, retry with increased priority.
> - */
> - if (compact_result == COMPACT_DEFERRED ||
> - compact_result == COMPACT_CONTENDED ||
> - compact_result == COMPACT_PARTIAL_SKIPPED)
> - goto check_priority;
> -
> - /*
> - * !costly requests are much more important than __GFP_RETRY_MAYFAIL
> - * costly ones because they are de facto nofail and invoke OOM
> - * killer to move on while costly can fail and users are ready
> - * to cope with that. 1/4 retries is rather arbitrary but we
> - * would need much more detailed feedback from compaction to
> - * make a better decision.
> - */
> - if (order > PAGE_ALLOC_COSTLY_ORDER)
> - max_retries /= 4;
> - if (*compaction_retries <= max_retries) {
> - ret = true;
> - goto out;
> - }
> -
> - /*
> - * Make sure there are attempts at the highest priority if we exhausted
> - * all retries or failed at the lower priorities.
> + * Compaction failed. Retry with increasing priority.
> */
> -check_priority:
> min_priority = (order > PAGE_ALLOC_COSTLY_ORDER) ?
> MIN_COMPACT_COSTLY_PRIORITY : MIN_COMPACT_PRIORITY;
>
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 2/5] mm: compaction: simplify should_compact_retry()
2023-05-29 13:03 ` Vlastimil Babka
@ 2023-05-29 16:38 ` Johannes Weiner
2023-06-02 14:47 ` Johannes Weiner
0 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-29 16:38 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Andrew Morton, Mel Gorman, Michal Hocko, linux-mm, linux-kernel,
kernel-team
On Mon, May 29, 2023 at 03:03:52PM +0200, Vlastimil Babka wrote:
> On 5/19/23 14:39, Johannes Weiner wrote:
> > The different branches for retry are unnecessarily complicated. There
> > are really only three outcomes: progress (retry n times), skipped
> > (retry if reclaim can help), failed (retry with higher priority).
> >
> > Rearrange the branches and the retry counter to make it simpler.
> >
> > v2:
> > - fix trace point build (Mel)
> > - fix max_retries logic for costly allocs (Huang)
> >
> > Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
> > ---
> > mm/page_alloc.c | 53 +++++++++++++++----------------------------------
> > 1 file changed, 16 insertions(+), 37 deletions(-)
> >
> > diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> > index 5a84a0bebc37..72660e924b95 100644
> > --- a/mm/page_alloc.c
> > +++ b/mm/page_alloc.c
> > @@ -3772,16 +3772,22 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> > * Compaction managed to coalesce some page blocks, but the
> > * allocation failed presumably due to a race. Retry some.
> > */
> > - if (compact_result == COMPACT_SUCCESS)
> > - (*compaction_retries)++;
> > + if (compact_result == COMPACT_SUCCESS) {
> > + /*
> > + * !costly requests are much more important than
> > + * __GFP_RETRY_MAYFAIL costly ones because they are de
> > + * facto nofail and invoke OOM killer to move on while
> > + * costly can fail and users are ready to cope with
> > + * that. 1/4 retries is rather arbitrary but we would
> > + * need much more detailed feedback from compaction to
> > + * make a better decision.
> > + */
> > + if (order > PAGE_ALLOC_COSTLY_ORDER)
> > + max_retries /= 4;
> >
> > - /*
> > - * All zones were scanned completely and still no result. It
> > - * doesn't really make much sense to retry except when the
> > - * failure could be caused by insufficient priority
> > - */
> > - if (compact_result == COMPACT_COMPLETE)
> > - goto check_priority;
> > + ret = ++(*compaction_retries) <= max_retries;
> > + goto out;
>
> I think you simplified this part too much, so now once it runs out of
> retries, it will return false, while previously it would increase the priority.
Oops, I'll send a delta fix to Andrew tomorrow. Thanks!
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 2/5] mm: compaction: simplify should_compact_retry()
2023-05-29 16:38 ` Johannes Weiner
@ 2023-06-02 14:47 ` Johannes Weiner
2023-06-06 12:58 ` Vlastimil Babka
0 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-06-02 14:47 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Andrew Morton, Mel Gorman, Michal Hocko, linux-mm, linux-kernel,
kernel-team
On Mon, May 29, 2023 at 12:38:07PM -0400, Johannes Weiner wrote:
> On Mon, May 29, 2023 at 03:03:52PM +0200, Vlastimil Babka wrote:
> > I think you simplified this part too much, so now once it runs out of
> > retries, it will return false, while previously it would increase the priority.
Here is the delta fix. If this looks good to everybody, can you please
fold this into the patch you have in tree? Thanks!
---
From 4b9429f9ef04fcb7bb5ffae0db8ea113b26d097b Mon Sep 17 00:00:00 2001
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Fri, 2 Jun 2023 16:02:37 +0200
Subject: [PATCH] mm: compaction: simplify should_compact_retry() fix
Vlastimil points out an unintended change. Previously when hitting
max_retries we'd bump the priority level and restart the loop. Now we
bail out and fail instead. Restore the original behavior.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/page_alloc.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 72660e924b95..e7d7db36582b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3768,6 +3768,15 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
if (fatal_signal_pending(current))
return false;
+ /*
+ * Compaction was skipped due to a lack of free order-0
+ * migration targets. Continue if reclaim can help.
+ */
+ if (compact_result == COMPACT_SKIPPED) {
+ ret = compaction_zonelist_suitable(ac, order, alloc_flags);
+ goto out;
+ }
+
/*
* Compaction managed to coalesce some page blocks, but the
* allocation failed presumably due to a race. Retry some.
@@ -3785,17 +3794,10 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
if (order > PAGE_ALLOC_COSTLY_ORDER)
max_retries /= 4;
- ret = ++(*compaction_retries) <= max_retries;
- goto out;
- }
-
- /*
- * Compaction was skipped due to a lack of free order-0
- * migration targets. Continue if reclaim can help.
- */
- if (compact_result == COMPACT_SKIPPED) {
- ret = compaction_zonelist_suitable(ac, order, alloc_flags);
- goto out;
+ if (++(*compaction_retries) <= max_retries) {
+ ret = true;
+ goto out;
+ }
}
/*
--
2.40.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 2/5] mm: compaction: simplify should_compact_retry()
2023-06-02 14:47 ` Johannes Weiner
@ 2023-06-06 12:58 ` Vlastimil Babka
0 siblings, 0 replies; 17+ messages in thread
From: Vlastimil Babka @ 2023-06-06 12:58 UTC (permalink / raw)
To: Johannes Weiner
Cc: Andrew Morton, Mel Gorman, Michal Hocko, linux-mm, linux-kernel,
kernel-team
On 6/2/23 16:47, Johannes Weiner wrote:
> On Mon, May 29, 2023 at 12:38:07PM -0400, Johannes Weiner wrote:
>> On Mon, May 29, 2023 at 03:03:52PM +0200, Vlastimil Babka wrote:
>> > I think you simplified this part too much, so now once it runs out of
>> > retries, it will return false, while previously it would increase the priority.
>
> Here is the delta fix. If this looks good to everybody, can you please
> fold this into the patch you have in tree? Thanks!
>
> ---
> From 4b9429f9ef04fcb7bb5ffae0db8ea113b26d097b Mon Sep 17 00:00:00 2001
> From: Johannes Weiner <hannes@cmpxchg.org>
> Date: Fri, 2 Jun 2023 16:02:37 +0200
> Subject: [PATCH] mm: compaction: simplify should_compact_retry() fix
>
> Vlastimil points out an unintended change. Previously when hitting
> max_retries we'd bump the priority level and restart the loop. Now we
> bail out and fail instead. Restore the original behavior.
>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
For the 2/5 +fix
Acked-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> mm/page_alloc.c | 24 +++++++++++++-----------
> 1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 72660e924b95..e7d7db36582b 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3768,6 +3768,15 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> if (fatal_signal_pending(current))
> return false;
>
> + /*
> + * Compaction was skipped due to a lack of free order-0
> + * migration targets. Continue if reclaim can help.
> + */
> + if (compact_result == COMPACT_SKIPPED) {
> + ret = compaction_zonelist_suitable(ac, order, alloc_flags);
> + goto out;
> + }
> +
> /*
> * Compaction managed to coalesce some page blocks, but the
> * allocation failed presumably due to a race. Retry some.
> @@ -3785,17 +3794,10 @@ should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
> if (order > PAGE_ALLOC_COSTLY_ORDER)
> max_retries /= 4;
>
> - ret = ++(*compaction_retries) <= max_retries;
> - goto out;
> - }
> -
> - /*
> - * Compaction was skipped due to a lack of free order-0
> - * migration targets. Continue if reclaim can help.
> - */
> - if (compact_result == COMPACT_SKIPPED) {
> - ret = compaction_zonelist_suitable(ac, order, alloc_flags);
> - goto out;
> + if (++(*compaction_retries) <= max_retries) {
> + ret = true;
> + goto out;
> + }
> }
>
> /*
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/5] mm: compaction: refactor __compaction_suitable()
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
2023-05-19 12:39 ` [PATCH 1/5] mm: compaction: remove compaction result helpers Johannes Weiner
2023-05-19 12:39 ` [PATCH 2/5] mm: compaction: simplify should_compact_retry() Johannes Weiner
@ 2023-05-19 12:39 ` Johannes Weiner
2023-05-29 17:11 ` Vlastimil Babka
2023-05-19 12:39 ` [PATCH 4/5] mm: compaction: remove unnecessary is_via_compact_memory() checks Johannes Weiner
` (2 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-19 12:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
__compaction_suitable() is supposed to check for available migration
targets. However, it also checks whether the operation was requested
via /proc/sys/vm/compact_memory, and whether the original allocation
request can already succeed. These don't apply to all callsites.
Move the checks out to the callers, so that later patches can deal
with them one by one. No functional change intended.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/compaction.h | 4 +-
mm/compaction.c | 78 ++++++++++++++++++++++++--------------
mm/vmscan.c | 35 ++++++++++-------
3 files changed, 73 insertions(+), 44 deletions(-)
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 1f0328a2ba48..9f7cf3e1bf89 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -90,7 +90,7 @@ extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
struct page **page);
extern void reset_isolation_suitable(pg_data_t *pgdat);
extern enum compact_result compaction_suitable(struct zone *zone, int order,
- unsigned int alloc_flags, int highest_zoneidx);
+ int highest_zoneidx);
extern void compaction_defer_reset(struct zone *zone, int order,
bool alloc_success);
@@ -108,7 +108,7 @@ static inline void reset_isolation_suitable(pg_data_t *pgdat)
}
static inline enum compact_result compaction_suitable(struct zone *zone, int order,
- int alloc_flags, int highest_zoneidx)
+ int highest_zoneidx)
{
return COMPACT_SKIPPED;
}
diff --git a/mm/compaction.c b/mm/compaction.c
index c9a4b6dffcf2..8f61cfa87c49 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2206,24 +2206,10 @@ static enum compact_result compact_finished(struct compact_control *cc)
}
static enum compact_result __compaction_suitable(struct zone *zone, int order,
- unsigned int alloc_flags,
int highest_zoneidx,
unsigned long wmark_target)
{
unsigned long watermark;
-
- if (is_via_compact_memory(order))
- return COMPACT_CONTINUE;
-
- watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
- /*
- * If watermarks for high-order allocation are already met, there
- * should be no need for compaction at all.
- */
- if (zone_watermark_ok(zone, order, watermark, highest_zoneidx,
- alloc_flags))
- return COMPACT_SUCCESS;
-
/*
* Watermarks for order-0 must be met for compaction to be able to
* isolate free pages for migration targets. This means that the
@@ -2256,13 +2242,12 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
* COMPACT_CONTINUE - If compaction should run now
*/
enum compact_result compaction_suitable(struct zone *zone, int order,
- unsigned int alloc_flags,
int highest_zoneidx)
{
enum compact_result ret;
int fragindex;
- ret = __compaction_suitable(zone, order, alloc_flags, highest_zoneidx,
+ ret = __compaction_suitable(zone, order, highest_zoneidx,
zone_page_state(zone, NR_FREE_PAGES));
/*
* fragmentation index determines if allocation failures are due to
@@ -2306,7 +2291,16 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
ac->highest_zoneidx, ac->nodemask) {
unsigned long available;
- enum compact_result compact_result;
+ unsigned long watermark;
+
+ if (is_via_compact_memory(order))
+ return true;
+
+ /* Allocation can already succeed, nothing to do */
+ watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
+ if (zone_watermark_ok(zone, order, watermark,
+ ac->highest_zoneidx, alloc_flags))
+ continue;
/*
* Do not consider all the reclaimable memory because we do not
@@ -2316,9 +2310,8 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
*/
available = zone_reclaimable_pages(zone) / order;
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
- compact_result = __compaction_suitable(zone, order, alloc_flags,
- ac->highest_zoneidx, available);
- if (compact_result == COMPACT_CONTINUE)
+ if (__compaction_suitable(zone, order, ac->highest_zoneidx,
+ available) == COMPACT_CONTINUE)
return true;
}
@@ -2348,11 +2341,23 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
INIT_LIST_HEAD(&cc->migratepages);
cc->migratetype = gfp_migratetype(cc->gfp_mask);
- ret = compaction_suitable(cc->zone, cc->order, cc->alloc_flags,
- cc->highest_zoneidx);
- /* Compaction is likely to fail */
- if (ret == COMPACT_SUCCESS || ret == COMPACT_SKIPPED)
- return ret;
+
+ if (!is_via_compact_memory(cc->order)) {
+ unsigned long watermark;
+
+ /* Allocation can already succeed, nothing to do */
+ watermark = wmark_pages(cc->zone,
+ cc->alloc_flags & ALLOC_WMARK_MASK);
+ if (zone_watermark_ok(cc->zone, cc->order, watermark,
+ cc->highest_zoneidx, cc->alloc_flags))
+ return COMPACT_SUCCESS;
+
+ ret = compaction_suitable(cc->zone, cc->order,
+ cc->highest_zoneidx);
+ /* Compaction is likely to fail */
+ if (ret == COMPACT_SKIPPED)
+ return ret;
+ }
/*
* Clear pageblock skip if there were failures recently and compaction
@@ -2845,7 +2850,16 @@ static bool kcompactd_node_suitable(pg_data_t *pgdat)
if (!populated_zone(zone))
continue;
- if (compaction_suitable(zone, pgdat->kcompactd_max_order, 0,
+ if (is_via_compact_memory(pgdat->kcompactd_max_order))
+ return true;
+
+ /* Allocation can already succeed, check other zones */
+ if (zone_watermark_ok(zone, pgdat->kcompactd_max_order,
+ min_wmark_pages(zone),
+ highest_zoneidx, 0))
+ continue;
+
+ if (compaction_suitable(zone, pgdat->kcompactd_max_order,
highest_zoneidx) == COMPACT_CONTINUE)
return true;
}
@@ -2883,10 +2897,18 @@ static void kcompactd_do_work(pg_data_t *pgdat)
if (compaction_deferred(zone, cc.order))
continue;
- if (compaction_suitable(zone, cc.order, 0, zoneid) !=
- COMPACT_CONTINUE)
+ if (is_via_compact_memory(cc.order))
+ goto compact;
+
+ /* Allocation can already succeed, nothing to do */
+ if (zone_watermark_ok(zone, cc.order,
+ min_wmark_pages(zone), zoneid, 0))
continue;
+ if (compaction_suitable(zone, cc.order,
+ zoneid) != COMPACT_CONTINUE)
+ continue;
+compact:
if (kthread_should_stop())
return;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d257916f39e5..c9c0f3e081f5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6397,14 +6397,17 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
if (!managed_zone(zone))
continue;
- switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
- case COMPACT_SUCCESS:
- case COMPACT_CONTINUE:
+ if (sc->order == -1) /* is_via_compact_memory() */
+ return false;
+
+ /* Allocation can already succeed, nothing to do */
+ if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
+ sc->reclaim_idx, 0))
+ return false;
+
+ if (compaction_suitable(zone, sc->order,
+ sc->reclaim_idx) == COMPACT_CONTINUE)
return false;
- default:
- /* check next zone */
- ;
- }
}
/*
@@ -6592,16 +6595,20 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
{
unsigned long watermark;
- enum compact_result suitable;
- suitable = compaction_suitable(zone, sc->order, 0, sc->reclaim_idx);
- if (suitable == COMPACT_SUCCESS)
- /* Allocation should succeed already. Don't reclaim. */
+ if (sc->order == -1) /* is_via_compact_memory() */
+ goto suitable;
+
+ /* Allocation can already succeed, nothing to do */
+ if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
+ sc->reclaim_idx, 0))
return true;
- if (suitable == COMPACT_SKIPPED)
- /* Compaction cannot yet proceed. Do reclaim. */
- return false;
+ /* Compaction cannot yet proceed. Do reclaim. */
+ if (compaction_suitable(zone, sc->order,
+ sc->reclaim_idx) == COMPACT_SKIPPED)
+ return false;
+suitable:
/*
* Compaction is already possible, but it takes time to run and there
* are potentially other callers using the pages just freed. So proceed
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 3/5] mm: compaction: refactor __compaction_suitable()
2023-05-19 12:39 ` [PATCH 3/5] mm: compaction: refactor __compaction_suitable() Johannes Weiner
@ 2023-05-29 17:11 ` Vlastimil Babka
2023-06-02 14:49 ` Johannes Weiner
0 siblings, 1 reply; 17+ messages in thread
From: Vlastimil Babka @ 2023-05-29 17:11 UTC (permalink / raw)
To: Johannes Weiner, Andrew Morton
Cc: Mel Gorman, Michal Hocko, linux-mm, linux-kernel, kernel-team
On 5/19/23 14:39, Johannes Weiner wrote:
> __compaction_suitable() is supposed to check for available migration
> targets. However, it also checks whether the operation was requested
> via /proc/sys/vm/compact_memory, and whether the original allocation
> request can already succeed. These don't apply to all callsites.
>
> Move the checks out to the callers, so that later patches can deal
> with them one by one. No functional change intended.
>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Note comment on compaction_suitable() still mentions COMPACT_SUCCESS, that
is no longer possible, so delete that line?
Also on closer look, both compaction_suitable() and __compaction_suitable()
could now simply return bool. The callers use it that way anyway. There
would just be some extra fiddling internally aroud the tracepoint.
> ---
> include/linux/compaction.h | 4 +-
> mm/compaction.c | 78 ++++++++++++++++++++++++--------------
> mm/vmscan.c | 35 ++++++++++-------
> 3 files changed, 73 insertions(+), 44 deletions(-)
>
> diff --git a/include/linux/compaction.h b/include/linux/compaction.h
> index 1f0328a2ba48..9f7cf3e1bf89 100644
> --- a/include/linux/compaction.h
> +++ b/include/linux/compaction.h
> @@ -90,7 +90,7 @@ extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
> struct page **page);
> extern void reset_isolation_suitable(pg_data_t *pgdat);
> extern enum compact_result compaction_suitable(struct zone *zone, int order,
> - unsigned int alloc_flags, int highest_zoneidx);
> + int highest_zoneidx);
>
> extern void compaction_defer_reset(struct zone *zone, int order,
> bool alloc_success);
> @@ -108,7 +108,7 @@ static inline void reset_isolation_suitable(pg_data_t *pgdat)
> }
>
> static inline enum compact_result compaction_suitable(struct zone *zone, int order,
> - int alloc_flags, int highest_zoneidx)
> + int highest_zoneidx)
> {
> return COMPACT_SKIPPED;
> }
> diff --git a/mm/compaction.c b/mm/compaction.c
> index c9a4b6dffcf2..8f61cfa87c49 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -2206,24 +2206,10 @@ static enum compact_result compact_finished(struct compact_control *cc)
> }
>
> static enum compact_result __compaction_suitable(struct zone *zone, int order,
> - unsigned int alloc_flags,
> int highest_zoneidx,
> unsigned long wmark_target)
> {
> unsigned long watermark;
> -
> - if (is_via_compact_memory(order))
> - return COMPACT_CONTINUE;
> -
> - watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
> - /*
> - * If watermarks for high-order allocation are already met, there
> - * should be no need for compaction at all.
> - */
> - if (zone_watermark_ok(zone, order, watermark, highest_zoneidx,
> - alloc_flags))
> - return COMPACT_SUCCESS;
> -
> /*
> * Watermarks for order-0 must be met for compaction to be able to
> * isolate free pages for migration targets. This means that the
> @@ -2256,13 +2242,12 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
> * COMPACT_CONTINUE - If compaction should run now
> */
> enum compact_result compaction_suitable(struct zone *zone, int order,
> - unsigned int alloc_flags,
> int highest_zoneidx)
> {
> enum compact_result ret;
> int fragindex;
>
> - ret = __compaction_suitable(zone, order, alloc_flags, highest_zoneidx,
> + ret = __compaction_suitable(zone, order, highest_zoneidx,
> zone_page_state(zone, NR_FREE_PAGES));
> /*
> * fragmentation index determines if allocation failures are due to
> @@ -2306,7 +2291,16 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
> for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
> ac->highest_zoneidx, ac->nodemask) {
> unsigned long available;
> - enum compact_result compact_result;
> + unsigned long watermark;
> +
> + if (is_via_compact_memory(order))
> + return true;
> +
> + /* Allocation can already succeed, nothing to do */
> + watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
> + if (zone_watermark_ok(zone, order, watermark,
> + ac->highest_zoneidx, alloc_flags))
> + continue;
>
> /*
> * Do not consider all the reclaimable memory because we do not
> @@ -2316,9 +2310,8 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
> */
> available = zone_reclaimable_pages(zone) / order;
> available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
> - compact_result = __compaction_suitable(zone, order, alloc_flags,
> - ac->highest_zoneidx, available);
> - if (compact_result == COMPACT_CONTINUE)
> + if (__compaction_suitable(zone, order, ac->highest_zoneidx,
> + available) == COMPACT_CONTINUE)
> return true;
> }
>
> @@ -2348,11 +2341,23 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
> INIT_LIST_HEAD(&cc->migratepages);
>
> cc->migratetype = gfp_migratetype(cc->gfp_mask);
> - ret = compaction_suitable(cc->zone, cc->order, cc->alloc_flags,
> - cc->highest_zoneidx);
> - /* Compaction is likely to fail */
> - if (ret == COMPACT_SUCCESS || ret == COMPACT_SKIPPED)
> - return ret;
> +
> + if (!is_via_compact_memory(cc->order)) {
> + unsigned long watermark;
> +
> + /* Allocation can already succeed, nothing to do */
> + watermark = wmark_pages(cc->zone,
> + cc->alloc_flags & ALLOC_WMARK_MASK);
> + if (zone_watermark_ok(cc->zone, cc->order, watermark,
> + cc->highest_zoneidx, cc->alloc_flags))
> + return COMPACT_SUCCESS;
> +
> + ret = compaction_suitable(cc->zone, cc->order,
> + cc->highest_zoneidx);
> + /* Compaction is likely to fail */
> + if (ret == COMPACT_SKIPPED)
> + return ret;
> + }
>
> /*
> * Clear pageblock skip if there were failures recently and compaction
> @@ -2845,7 +2850,16 @@ static bool kcompactd_node_suitable(pg_data_t *pgdat)
> if (!populated_zone(zone))
> continue;
>
> - if (compaction_suitable(zone, pgdat->kcompactd_max_order, 0,
> + if (is_via_compact_memory(pgdat->kcompactd_max_order))
> + return true;
> +
> + /* Allocation can already succeed, check other zones */
> + if (zone_watermark_ok(zone, pgdat->kcompactd_max_order,
> + min_wmark_pages(zone),
> + highest_zoneidx, 0))
> + continue;
> +
> + if (compaction_suitable(zone, pgdat->kcompactd_max_order,
> highest_zoneidx) == COMPACT_CONTINUE)
> return true;
> }
> @@ -2883,10 +2897,18 @@ static void kcompactd_do_work(pg_data_t *pgdat)
> if (compaction_deferred(zone, cc.order))
> continue;
>
> - if (compaction_suitable(zone, cc.order, 0, zoneid) !=
> - COMPACT_CONTINUE)
> + if (is_via_compact_memory(cc.order))
> + goto compact;
> +
> + /* Allocation can already succeed, nothing to do */
> + if (zone_watermark_ok(zone, cc.order,
> + min_wmark_pages(zone), zoneid, 0))
> continue;
>
> + if (compaction_suitable(zone, cc.order,
> + zoneid) != COMPACT_CONTINUE)
> + continue;
> +compact:
> if (kthread_should_stop())
> return;
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index d257916f39e5..c9c0f3e081f5 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -6397,14 +6397,17 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
> if (!managed_zone(zone))
> continue;
>
> - switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
> - case COMPACT_SUCCESS:
> - case COMPACT_CONTINUE:
> + if (sc->order == -1) /* is_via_compact_memory() */
> + return false;
> +
> + /* Allocation can already succeed, nothing to do */
> + if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
> + sc->reclaim_idx, 0))
> + return false;
> +
> + if (compaction_suitable(zone, sc->order,
> + sc->reclaim_idx) == COMPACT_CONTINUE)
> return false;
> - default:
> - /* check next zone */
> - ;
> - }
> }
>
> /*
> @@ -6592,16 +6595,20 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
> static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
> {
> unsigned long watermark;
> - enum compact_result suitable;
>
> - suitable = compaction_suitable(zone, sc->order, 0, sc->reclaim_idx);
> - if (suitable == COMPACT_SUCCESS)
> - /* Allocation should succeed already. Don't reclaim. */
> + if (sc->order == -1) /* is_via_compact_memory() */
> + goto suitable;
> +
> + /* Allocation can already succeed, nothing to do */
> + if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
> + sc->reclaim_idx, 0))
> return true;
> - if (suitable == COMPACT_SKIPPED)
> - /* Compaction cannot yet proceed. Do reclaim. */
> - return false;
>
> + /* Compaction cannot yet proceed. Do reclaim. */
> + if (compaction_suitable(zone, sc->order,
> + sc->reclaim_idx) == COMPACT_SKIPPED)
> + return false;
> +suitable:
> /*
> * Compaction is already possible, but it takes time to run and there
> * are potentially other callers using the pages just freed. So proceed
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 3/5] mm: compaction: refactor __compaction_suitable()
2023-05-29 17:11 ` Vlastimil Babka
@ 2023-06-02 14:49 ` Johannes Weiner
0 siblings, 0 replies; 17+ messages in thread
From: Johannes Weiner @ 2023-06-02 14:49 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Andrew Morton, Mel Gorman, Michal Hocko, linux-mm, linux-kernel,
kernel-team
On Mon, May 29, 2023 at 07:11:35PM +0200, Vlastimil Babka wrote:
> On 5/19/23 14:39, Johannes Weiner wrote:
> > __compaction_suitable() is supposed to check for available migration
> > targets. However, it also checks whether the operation was requested
> > via /proc/sys/vm/compact_memory, and whether the original allocation
> > request can already succeed. These don't apply to all callsites.
> >
> > Move the checks out to the callers, so that later patches can deal
> > with them one by one. No functional change intended.
> >
> > Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
>
> Acked-by: Vlastimil Babka <vbabka@suse.cz>
>
> Note comment on compaction_suitable() still mentions COMPACT_SUCCESS, that
> is no longer possible, so delete that line?
Good catch, let's remove it.
> Also on closer look, both compaction_suitable() and __compaction_suitable()
> could now simply return bool. The callers use it that way anyway. There
> would just be some extra fiddling internally aroud the tracepoint.
Also a great idea. This will raise conflicts in later changes, so I'll
send a new patch to go on top of the stack.
Andrew, can you please fold this? Thanks!
---
From abaf21e8dc2a3ed2aa181e0c89403807e5cea67d Mon Sep 17 00:00:00 2001
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Fri, 2 Jun 2023 10:13:15 -0400
Subject: [PATCH] mm: compaction: refactor __compaction_suitable() fix
Vlastimil points out the function comment is stale now. Update it.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/compaction.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index 8f61cfa87c49..0503cb59c1cb 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2238,7 +2238,6 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
* compaction_suitable: Is this suitable to run compaction on this zone now?
* Returns
* COMPACT_SKIPPED - If there are too few free pages for compaction
- * COMPACT_SUCCESS - If the allocation would succeed without compaction
* COMPACT_CONTINUE - If compaction should run now
*/
enum compact_result compaction_suitable(struct zone *zone, int order,
--
2.40.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/5] mm: compaction: remove unnecessary is_via_compact_memory() checks
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
` (2 preceding siblings ...)
2023-05-19 12:39 ` [PATCH 3/5] mm: compaction: refactor __compaction_suitable() Johannes Weiner
@ 2023-05-19 12:39 ` Johannes Weiner
2023-05-29 17:12 ` Vlastimil Babka
2023-05-19 12:39 ` [PATCH 5/5] mm: compaction: drop redundant watermark check in compaction_zonelist_suitable() Johannes Weiner
2023-06-02 15:12 ` [PATCH 6/5] mm: compaction: have compaction_suitable() return bool Johannes Weiner
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-19 12:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
Remove from all paths not reachable via /proc/sys/vm/compact_memory.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/compaction.c | 11 +----------
mm/vmscan.c | 8 +-------
2 files changed, 2 insertions(+), 17 deletions(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index 8f61cfa87c49..83ecbc829c62 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2293,9 +2293,6 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
unsigned long available;
unsigned long watermark;
- if (is_via_compact_memory(order))
- return true;
-
/* Allocation can already succeed, nothing to do */
watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
if (zone_watermark_ok(zone, order, watermark,
@@ -2850,9 +2847,6 @@ static bool kcompactd_node_suitable(pg_data_t *pgdat)
if (!populated_zone(zone))
continue;
- if (is_via_compact_memory(pgdat->kcompactd_max_order))
- return true;
-
/* Allocation can already succeed, check other zones */
if (zone_watermark_ok(zone, pgdat->kcompactd_max_order,
min_wmark_pages(zone),
@@ -2897,9 +2891,6 @@ static void kcompactd_do_work(pg_data_t *pgdat)
if (compaction_deferred(zone, cc.order))
continue;
- if (is_via_compact_memory(cc.order))
- goto compact;
-
/* Allocation can already succeed, nothing to do */
if (zone_watermark_ok(zone, cc.order,
min_wmark_pages(zone), zoneid, 0))
@@ -2908,7 +2899,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
if (compaction_suitable(zone, cc.order,
zoneid) != COMPACT_CONTINUE)
continue;
-compact:
+
if (kthread_should_stop())
return;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c9c0f3e081f5..c0cfa9b86b48 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6397,9 +6397,6 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
if (!managed_zone(zone))
continue;
- if (sc->order == -1) /* is_via_compact_memory() */
- return false;
-
/* Allocation can already succeed, nothing to do */
if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
sc->reclaim_idx, 0))
@@ -6596,9 +6593,6 @@ static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
{
unsigned long watermark;
- if (sc->order == -1) /* is_via_compact_memory() */
- goto suitable;
-
/* Allocation can already succeed, nothing to do */
if (zone_watermark_ok(zone, sc->order, min_wmark_pages(zone),
sc->reclaim_idx, 0))
@@ -6608,7 +6602,7 @@ static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
if (compaction_suitable(zone, sc->order,
sc->reclaim_idx) == COMPACT_SKIPPED)
return false;
-suitable:
+
/*
* Compaction is already possible, but it takes time to run and there
* are potentially other callers using the pages just freed. So proceed
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 5/5] mm: compaction: drop redundant watermark check in compaction_zonelist_suitable()
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
` (3 preceding siblings ...)
2023-05-19 12:39 ` [PATCH 4/5] mm: compaction: remove unnecessary is_via_compact_memory() checks Johannes Weiner
@ 2023-05-19 12:39 ` Johannes Weiner
2023-05-29 17:12 ` Vlastimil Babka
2023-06-02 15:12 ` [PATCH 6/5] mm: compaction: have compaction_suitable() return bool Johannes Weiner
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-05-19 12:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
The watermark check in compaction_zonelist_suitable(), called from
should_compact_retry(), is sandwiched between two watermark checks
already: before, there are freelist attempts as part of direct reclaim
and direct compaction; after, there is a last-minute freelist attempt
in __alloc_pages_may_oom().
The check in compaction_zonelist_suitable() isn't necessary. Kill it.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
mm/compaction.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index 83ecbc829c62..40ce4e6dd17e 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2291,13 +2291,6 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
ac->highest_zoneidx, ac->nodemask) {
unsigned long available;
- unsigned long watermark;
-
- /* Allocation can already succeed, nothing to do */
- watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
- if (zone_watermark_ok(zone, order, watermark,
- ac->highest_zoneidx, alloc_flags))
- continue;
/*
* Do not consider all the reclaimable memory because we do not
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 5/5] mm: compaction: drop redundant watermark check in compaction_zonelist_suitable()
2023-05-19 12:39 ` [PATCH 5/5] mm: compaction: drop redundant watermark check in compaction_zonelist_suitable() Johannes Weiner
@ 2023-05-29 17:12 ` Vlastimil Babka
0 siblings, 0 replies; 17+ messages in thread
From: Vlastimil Babka @ 2023-05-29 17:12 UTC (permalink / raw)
To: Johannes Weiner, Andrew Morton
Cc: Mel Gorman, Michal Hocko, linux-mm, linux-kernel, kernel-team
On 5/19/23 14:39, Johannes Weiner wrote:
> The watermark check in compaction_zonelist_suitable(), called from
> should_compact_retry(), is sandwiched between two watermark checks
> already: before, there are freelist attempts as part of direct reclaim
> and direct compaction; after, there is a last-minute freelist attempt
> in __alloc_pages_may_oom().
>
> The check in compaction_zonelist_suitable() isn't necessary. Kill it.
>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 6/5] mm: compaction: have compaction_suitable() return bool
2023-05-19 12:39 [PATCH 0/5] mm: compaction: cleanups & simplifications Johannes Weiner
` (4 preceding siblings ...)
2023-05-19 12:39 ` [PATCH 5/5] mm: compaction: drop redundant watermark check in compaction_zonelist_suitable() Johannes Weiner
@ 2023-06-02 15:12 ` Johannes Weiner
2023-06-06 13:04 ` Vlastimil Babka
5 siblings, 1 reply; 17+ messages in thread
From: Johannes Weiner @ 2023-06-02 15:12 UTC (permalink / raw)
To: Andrew Morton
Cc: Mel Gorman, Vlastimil Babka, Michal Hocko, linux-mm, linux-kernel,
kernel-team
Since it only returns COMPACT_CONTINUE or COMPACT_SKIPPED now, a bool
return value simplifies the callsites.
Suggested-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/compaction.h | 6 ++--
mm/compaction.c | 64 ++++++++++++++++++--------------------
mm/vmscan.c | 6 ++--
3 files changed, 36 insertions(+), 40 deletions(-)
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 9f7cf3e1bf89..57b16e69c19a 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -89,7 +89,7 @@ extern enum compact_result try_to_compact_pages(gfp_t gfp_mask,
const struct alloc_context *ac, enum compact_priority prio,
struct page **page);
extern void reset_isolation_suitable(pg_data_t *pgdat);
-extern enum compact_result compaction_suitable(struct zone *zone, int order,
+extern bool compaction_suitable(struct zone *zone, int order,
int highest_zoneidx);
extern void compaction_defer_reset(struct zone *zone, int order,
@@ -107,10 +107,10 @@ static inline void reset_isolation_suitable(pg_data_t *pgdat)
{
}
-static inline enum compact_result compaction_suitable(struct zone *zone, int order,
+static inline bool compaction_suitable(struct zone *zone, int order,
int highest_zoneidx)
{
- return COMPACT_SKIPPED;
+ return false;
}
static inline void kcompactd_run(int nid)
diff --git a/mm/compaction.c b/mm/compaction.c
index fdee5f1ac5a1..d354d8af157c 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2205,9 +2205,9 @@ static enum compact_result compact_finished(struct compact_control *cc)
return ret;
}
-static enum compact_result __compaction_suitable(struct zone *zone, int order,
- int highest_zoneidx,
- unsigned long wmark_target)
+static bool __compaction_suitable(struct zone *zone, int order,
+ int highest_zoneidx,
+ unsigned long wmark_target)
{
unsigned long watermark;
/*
@@ -2227,27 +2227,20 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
low_wmark_pages(zone) : min_wmark_pages(zone);
watermark += compact_gap(order);
- if (!__zone_watermark_ok(zone, 0, watermark, highest_zoneidx,
- ALLOC_CMA, wmark_target))
- return COMPACT_SKIPPED;
-
- return COMPACT_CONTINUE;
+ return __zone_watermark_ok(zone, 0, watermark, highest_zoneidx,
+ ALLOC_CMA, wmark_target);
}
/*
* compaction_suitable: Is this suitable to run compaction on this zone now?
- * Returns
- * COMPACT_SKIPPED - If there are too few free pages for compaction
- * COMPACT_CONTINUE - If compaction should run now
*/
-enum compact_result compaction_suitable(struct zone *zone, int order,
- int highest_zoneidx)
+bool compaction_suitable(struct zone *zone, int order, int highest_zoneidx)
{
- enum compact_result ret;
- int fragindex;
+ enum compact_result compact_result;
+ bool suitable;
- ret = __compaction_suitable(zone, order, highest_zoneidx,
- zone_page_state(zone, NR_FREE_PAGES));
+ suitable = __compaction_suitable(zone, order, highest_zoneidx,
+ zone_page_state(zone, NR_FREE_PAGES));
/*
* fragmentation index determines if allocation failures are due to
* low memory or external fragmentation
@@ -2264,17 +2257,24 @@ enum compact_result compaction_suitable(struct zone *zone, int order,
* excessive compaction for costly orders, but it should not be at the
* expense of system stability.
*/
- if (ret == COMPACT_CONTINUE && (order > PAGE_ALLOC_COSTLY_ORDER)) {
- fragindex = fragmentation_index(zone, order);
- if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
- ret = COMPACT_NOT_SUITABLE_ZONE;
+ if (suitable) {
+ compact_result = COMPACT_CONTINUE;
+ if (order > PAGE_ALLOC_COSTLY_ORDER) {
+ int fragindex = fragmentation_index(zone, order);
+
+ if (fragindex >= 0 &&
+ fragindex <= sysctl_extfrag_threshold) {
+ suitable = false;
+ compact_result = COMPACT_NOT_SUITABLE_ZONE;
+ }
+ }
+ } else {
+ compact_result = COMPACT_SKIPPED;
}
- trace_mm_compaction_suitable(zone, order, ret);
- if (ret == COMPACT_NOT_SUITABLE_ZONE)
- ret = COMPACT_SKIPPED;
+ trace_mm_compaction_suitable(zone, order, compact_result);
- return ret;
+ return suitable;
}
bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
@@ -2300,7 +2300,7 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
available = zone_reclaimable_pages(zone) / order;
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
if (__compaction_suitable(zone, order, ac->highest_zoneidx,
- available) == COMPACT_CONTINUE)
+ available))
return true;
}
@@ -2341,11 +2341,10 @@ compact_zone(struct compact_control *cc, struct capture_control *capc)
cc->highest_zoneidx, cc->alloc_flags))
return COMPACT_SUCCESS;
- ret = compaction_suitable(cc->zone, cc->order,
- cc->highest_zoneidx);
/* Compaction is likely to fail */
- if (ret == COMPACT_SKIPPED)
- return ret;
+ if (!compaction_suitable(cc->zone, cc->order,
+ cc->highest_zoneidx))
+ return COMPACT_SKIPPED;
}
/*
@@ -2846,7 +2845,7 @@ static bool kcompactd_node_suitable(pg_data_t *pgdat)
continue;
if (compaction_suitable(zone, pgdat->kcompactd_max_order,
- highest_zoneidx) == COMPACT_CONTINUE)
+ highest_zoneidx))
return true;
}
@@ -2888,8 +2887,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
min_wmark_pages(zone), zoneid, 0))
continue;
- if (compaction_suitable(zone, cc.order,
- zoneid) != COMPACT_CONTINUE)
+ if (!compaction_suitable(zone, cc.order, zoneid))
continue;
if (kthread_should_stop())
diff --git a/mm/vmscan.c b/mm/vmscan.c
index c0cfa9b86b48..e9a8ca124982 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6402,8 +6402,7 @@ static inline bool should_continue_reclaim(struct pglist_data *pgdat,
sc->reclaim_idx, 0))
return false;
- if (compaction_suitable(zone, sc->order,
- sc->reclaim_idx) == COMPACT_CONTINUE)
+ if (compaction_suitable(zone, sc->order, sc->reclaim_idx))
return false;
}
@@ -6599,8 +6598,7 @@ static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
return true;
/* Compaction cannot yet proceed. Do reclaim. */
- if (compaction_suitable(zone, sc->order,
- sc->reclaim_idx) == COMPACT_SKIPPED)
+ if (!compaction_suitable(zone, sc->order, sc->reclaim_idx))
return false;
/*
--
2.40.1
^ permalink raw reply related [flat|nested] 17+ messages in thread