Fragmentation avoidance improvements v5
Subsystems (8)
cover Fragmentation avoidance improvements v5
There are some big changes due to both Vlastimil's review feedback on v4 and some oddities spotted while answering his review. In some respects, the series is slightly less effective but the approach is more consistent and logical overall. The overhead is also lower from the first patch and stalls are less harmful in the last patch so overall I think it has much improved.
Changelog since v4
o Clarified changelogs in response to review
o Add a compile-time check on where Normal and DMA32 is (vbabka)
o Restart zone iteration properly in get_page_from_freelist (vbabka)
o Reduce overhead in the page allocation fast path (mel)
o Do not over-boost due to a fragmentation event (vbabka)
o Correct documentation of sysctl (mel)
o Really do not wake kswapd if the calling context forbids it (vbabka,mel)
o Do not shrink slab if boosting watermarks as premature
reclaim of slab can lead to regressions in IO benchmarks (mel)
o Take zone lock when boosting watermarks if necessary (vbabka)
Changelog since v3
o Rebase to 4.20-rc3
o Remove a stupid warning from the last patch
Changelog since v2
o Drop patch 5 as it was borderline
o Decrease timeout when stalling on fragmentation events
Changelog since v1
o Rebase to v4.20-rc1 for the THP __GFP_THISNODE patch in particular
o Add tracepoint to record fragmentation stall durations
o Add vmstat event to record that a fragmentation stall occurred
o Stalls now alter watermark boosting
o Stalls occur only when the allocation is about to fail
It has been noted before that fragmentation avoidance (aka anti-fragmentation) is not perfect. Given sufficient time or an adverse workload, memory gets fragmented and the long-term success of high-order allocations degrades. This series defines an adverse workload, a definition of external fragmentation events (including serious) ones and a series that reduces the level of those fragmentation events.
The details of the workload and the consequences are described in more detail in the changelogs. However, from patch 1, this is a high-level summary of the adverse workload. The exact details are found in the mmtests implementation.
The broad details of the workload are as follows;
1. Create an XFS filesystem (not specified in the configuration but done as part of the testing for this patch)
2. Start 4 fio threads that write a number of 64K files inefficiently. Inefficiently means that files are created on first access and not created in advance (fio parameterr create_on_open=1) and fallocate is not used (fallocate=none). With multiple IO issuers this creates a mix of slab and page cache allocations over time. The total size of the files is 150% physical memory so that the slabs and page cache pages get mixed
3. Warm up a number of fio read-only threads accessing the same files created in step 2. This part runs for the same length of time it took to create the files. It'll fault back in old data and further interleave slab and page cache allocations. As it's now low on memory due to step 2, fragmentation occurs as pageblocks get stolen.
4. While step 3 is still running, start a process that tries to allocate 75% of memory as huge pages with a number of threads. The number of threads is based on a (NR_CPUS_SOCKET - NR_FIO_THREADS)/4 to avoid THP threads contending with fio, any other threads or forcing cross-NUMA scheduling. Note that the test has not been used on a machine with less than 8 cores. The benchmark records whether huge pages were allocated and what the fault latency was in microseconds
5. Measure the number of events potentially causing external fragmentation, the fault latency and the huge page allocation success rate.
6. Cleanup
Overall the series reduces external fragmentation causing events by over 94% on 1 and 2 socket machines, which in turn impacts high-order allocation success rates over the long term. There are differences in latencies and high-order allocation success rates. Latencies are a mixed bag as they are vulnerable to exact system state and whether allocations succeeded so they are treated as a secondary metric.
Patch 1 uses lower zones if they are populated and have free memory
instead of fragmenting a higher zone. It's special cased to handle a Normal->DMA32 fallback with the reasons explained in the changelog.
Patch 2-4 boosts watermarks temporarily when an external fragmentation
event occurs. kswapd wakes to reclaim a small amount of old memory and then wakes kcompactd on completion to recover the system slightly. This introduces some overhead in the slowpath. The level of boosting can be tuned or disabled depending on the tolerance for fragmentation vs allocation latency.
Patch 5 stalls some movable allocation requests to let kswapd from patch 4
make some progress. The duration of the stalls is very low but it is possible to tune the system to avoid fragmentation events if larger stalls can be tolerated.
The bulk of the improvement in fragmentation avoidance is from patches 1-4 but patch 5 can deal with a rare corner case and provides the option of tuning a system for THP allocation success rates in exchange for some stalls to control fragmentation.
Documentation/sysctl/vm.txt | 44 +++++++ include/linux/mm.h | 2 + include/linux/mmzone.h | 14 ++- include/linux/vm_event_item.h | 1 + include/trace/events/kmem.h | 21 ++++ kernel/sysctl.c | 18 +++ mm/compaction.c | 2 +- mm/internal.h | 15 ++- mm/page_alloc.c | 263 ++++++++++++++++++++++++++++++++++++++---- mm/vmscan.c | 136 ++++++++++++++++++++-- mm/vmstat.c | 1 + 11 files changed, 473 insertions(+), 44 deletions(-)
Signature · 1 line
2.16.4
PATCH 1/5 mm, page_alloc: Spread allocations across zones before introducing fragmentation
The page allocator zone lists are iterated based on the watermarks of each zone which does not take anti-fragmentation into account. On x86, node 0 may have multiple zones while other nodes have one zone. A consequence is that tasks running on node 0 may fragment ZONE_NORMAL even though ZONE_DMA32 has plenty of free memory. This patch special cases the allocator fast path such that it'll try an allocation from a lower local zone before fragmenting a higher zone. In this case, stealing of pageblocks or orders larger than a pageblock are still allowed in the fast path as they are uninteresting from a fragmentation point of view.
This was evaluated using a benchmark designed to fragment memory before attempting THP allocations. It's implemented in mmtests as the following configurations
configs/config-global-dhp__workload_thpfioscale configs/config-global-dhp__workload_thpfioscale-defrag configs/config-global-dhp__workload_thpfioscale-madvhugepage
e.g. from mmtests
./run-mmtests.sh --run-monitor --config configs/config-global-dhp__workload_thpfioscale test-run-1
The broad details of the workload are as follows;
1. Create an XFS filesystem (not specified in the configuration but done as part of the testing for this patch).
2. Start 4 fio threads that write a number of 64K files inefficiently. Inefficiently means that files are created on first access and not created in advance (fio parameter create_on_open=1) and fallocate is not used (fallocate=none). With multiple IO issuers this creates a mix of slab and page cache allocations over time. The total size of the files is 150% physical memory so that the slabs and page cache pages get mixed.
3. Warm up a number of fio read-only processes accessing the same files created in step 2. This part runs for the same length of time it took to create the files. It'll refault old data and further interleave slab and page cache allocations. As it's now low on memory due to step 2, fragmentation occurs as pageblocks get stolen.
4. While step 3 is still running, start a process that tries to allocate 75% of memory as huge pages with a number of threads. The number of threads is based on a (NR_CPUS_SOCKET - NR_FIO_THREADS)/4 to avoid THP threads contending with fio, any other threads or forcing cross-NUMA scheduling. Note that the test has not been used on a machine with less than 8 cores. The benchmark records whether huge pages were allocated and what the fault latency was in microseconds.
5. Measure the number of events potentially causing external fragmentation, the fault latency and the huge page allocation success rate.
6. Cleanup the test files.
Note that due to the use of IO and page cache that this benchmark is not suitable for running on large machines where the time to fragment memory may be excessive. Also note that while this is one mix that generates fragmentation that it's not the only mix that generates fragmentation. Differences in workload that are more slab-intensive or whether SLUB is used with high-order pages may yield different results.
When the page allocator fragments memory, it records the event using the mm_page_alloc_extfrag ftrace event. If the fallback_order is smaller than a pageblock order (order-9 on 64-bit x86) then it's considered to be an "external fragmentation event" that may cause issues in the future. Hence, the primary metric here is the number of external fragmentation events that occur with order < 9. The secondary metric is allocation latency and huge page allocation success rates but note that differences in latencies and what the success rate also can affect the number of external fragmentation event which is why it's a secondary metric.
1-socket Skylake machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 1 THP allocating thread
--------------------------------------
4.20-rc3 extfrag events < order 9: 804694
4.20-rc3+patch: 408912 (49% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8
Amean fault-base-1 662.92 ( 0.00%) 653.58 * 1.41%*
Amean fault-huge-1 0.00 ( 0.00%) 0.00 ( 0.00%) 4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8Percentage huge-1 0.00 ( 0.00%) 0.00 ( 0.00%)
Fault latencies are slightly reduced while allocation success rates remain at zero as this configuration does not make any special effort to allocate THP and fio is heavily active at the time and either filling memory or keeping pages resident. However, a 49% reduction of serious fragmentation events reduces the changes of external fragmentation being a problem in the future.
Vlastimil asked during review for a breakdown of the allocation types that are falling back.
vanilla
3816 MIGRATE_UNMOVABLE
800845 MIGRATE_MOVABLE
33 MIGRATE_UNRECLAIMABLE
patch
735 MIGRATE_UNMOVABLE
408135 MIGRATE_MOVABLE
42 MIGRATE_UNRECLAIMABLE
The majority of the fallbacks are due to movable allocations and this is consistent for the workload throughout the series so will not be presented again as the primary source of fallbacks are movable allocations.
Movable fallbacks are sometimes considered "ok" to fallback because they can be migrated. The problem is that they can fill an unmovable/reclaimable pageblock causing those allocations to fallback later and polluting pageblocks with pages that cannot move. If there is a movable fallback, it is pretty much guaranteed to affect an unmovable/reclaimable pageblock and while it might not be enough to actually cause a unmovable/reclaimable fallback in the future, we cannot know that in advance so the patch takes the only option available to it. Hence, it's important to control them. This point is also consistent throughout the series and will not be repeated.
1-socket Skylake machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 291392
4.20-rc3+patch: 191187 (34% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8
Amean fault-base-1 1495.14 ( 0.00%) 1467.55 ( 1.85%)
Amean fault-huge-1 1098.48 ( 0.00%) 1127.11 ( -2.61%)thpfioscale Percentage Faults Huge
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8Percentage huge-1 78.57 ( 0.00%) 77.64 ( -1.18%)
Fragmentation events were reduced quite a bit although this is known to be a little variable. The latencies and allocation success rates are similar but they were already quite high.
2-socket Haswell machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 5 THP allocating threads
----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 215698
4.20-rc3+patch: 200210 (7% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8
Amean fault-base-5 1350.05 ( 0.00%) 1346.45 ( 0.27%)
Amean fault-huge-5 4181.01 ( 0.00%) 3418.60 ( 18.24%) 4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8Percentage huge-5 1.15 ( 0.00%) 0.78 ( -31.88%)
The reduction of external fragmentation events is slight and this is partially due to the removal of __GFP_THISNODE in commit ac5b2c18911f ("mm:
thp: relax __GFP_THISNODE for MADV_HUGEPAGE mappings") as THP allocations can now spill over to remote nodes instead of fragmenting local memory.
2-socket Haswell machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 166352
4.20-rc3+patch: 147463 (11% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8
Amean fault-base-5 6138.97 ( 0.00%) 6217.43 ( -1.28%)
Amean fault-huge-5 2294.28 ( 0.00%) 3163.33 * -37.88%*thpfioscale Percentage Faults Huge
4.20.0-rc3 4.20.0-rc3
vanilla lowzone-v5r8Percentage huge-5 96.82 ( 0.00%) 95.14 ( -1.74%)
There was a slight reduction in external fragmentation events although the latencies were higher. The allocation success rate is high enough that the system is struggling and there is quite a lot of parallel reclaim and compaction activity. There is also a certain degree of luck on whether processes start on node 0 or not for this patch but the relevance is reduced later in the series.
Overall, the patch reduces the number of external fragmentation causing events so the success of THP over long periods of time would be improved for this adverse workload.
--- mm/internal.h | 13 ++++--- mm/page_alloc.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 16 deletions(-)
mm/internal.h +9 -4
@@ -480,10 +480,15 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_OOM ALLOC_NO_WATERMARKS#endif -#define ALLOC_HARDER 0x10/* try to alloc harder */ -#define ALLOC_HIGH 0x20/* __GFP_HIGH set */ -#define ALLOC_CPUSET 0x40/* check for correct cpuset */ -#define ALLOC_CMA 0x80/* allow allocations from CMA areas */ +#define ALLOC_HARDER 0x10/* try to alloc harder */ +#define ALLOC_HIGH 0x20/* __GFP_HIGH set */ +#define ALLOC_CPUSET 0x40/* check for correct cpuset */ +#define ALLOC_CMA 0x80/* allow allocations from CMA areas */ +#ifdef CONFIG_ZONE_DMA32 +#define ALLOC_NOFRAGMENT 0x100/* avoid mixing pageblock types */ +#else +#define ALLOC_NOFRAGMENT 0x0 +#endif enum ttu_flags ;struct tlbflush_unmap_batch ;
mm/page_alloc.c +96 -12
222 lines not on this page · raw message
Signature · 1 line
2.16.4
Re: [PATCH 1/5] mm, page_alloc: Spread allocations across zones before introducing fragmentation
On 11/23/18 12:45 PM, Mel Gorman wrote:
...
Quoted 15 lines
Fault latencies are slightly reduced while allocation success rates remain at zero as this configuration does not make any special effort to allocate THP and fio is heavily active at the time and either filling memory or keeping pages resident. However, a 49% reduction of serious fragmentation events reduces the changes of external fragmentation being a problem in the future.
Vlastimil asked during review for a breakdown of the allocation types that are falling back.
vanilla
3816MIGRATE_UNMOVABLE
800845MIGRATE_MOVABLE
33MIGRATE_UNRECLAIMABLE
Quoted 4 lines
patch
735MIGRATE_UNMOVABLE
408135MIGRATE_MOVABLE
42MIGRATE_UNRECLAIMABLE
Nit: it's MIGRATE_RECLAIMABLE :)
Quoted 3 lines
The majority of the fallbacks are due to movable allocations and this is consistent for the workload throughout the series so will not be presented again as the primary source of fallbacks are movable allocations.
Note that I was more interested in the *reduction* of different kinds of fallbacks, not their ratios - that the majority is caused by movable allocations is fully expected.
And the results above actually show that while the reduction for MOVABLE is ~50%, the reduction for UNMOVABLE is actually 80%! IMHO that's great (better than I would expect, in fact), and good to know.
...
Quoted 5 lines
Overall, the patch reduces the number of external fragmentation causing events so the success of THP over long periods of time would be improved for this adverse workload.
Signed-off-by Mel Gorman <[email protected]>
PATCH 2/5 mm: Move zone watermark accesses behind an accessor
In reply to Mel GormanThis is a preparation patch only, no functional change.
--- include/linux/mmzone.h | 9 +++++---- mm/compaction.c | 2 +- mm/page_alloc.c | 12 ++++++------ 3 files changed, 12 insertions(+), 11 deletions(-)
include/linux/mmzone.h +5 -4
@@ -269,9 +269,10 @@ enum zone_watermarks {NR_WMARK }; -#define min_wmark_pages (z) (z->watermark[WMARK_MIN]) -#define low_wmark_pages (z) (z->watermark[WMARK_LOW]) -#define high_wmark_pages (z) (z->watermark[WMARK_HIGH]) +#define min_wmark_pages (z) (z->_watermark[WMARK_MIN]) +#define low_wmark_pages (z) (z->_watermark[WMARK_LOW]) +#define high_wmark_pages (z) (z->_watermark[WMARK_HIGH]) +#define wmark_pages (z, i) (z->_watermark[i])struct per_cpu_pages {int count;/* number of pages in the list */
@@ -362,7 +363,7 @@ struct zone {/* Read-mostly fields */ /* zone watermarks, access with *_wmark_pages(zone) macros */ -unsigned long watermark[NR_WMARK ]; +unsigned long _watermark[NR_WMARK ];unsigned long nr_reserved_highatomic;
mm/compaction.c +1 -1
@@ -1431,7 +1431,7 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,if (is_via_compact_memory (order))return COMPACT_CONTINUE ; - watermark = zone->watermark[alloc_flags &ALLOC_WMARK_MASK ]; + 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.
mm/page_alloc.c +6 -6
@@ -3376,7 +3376,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags, } } - mark = zone->watermark[alloc_flags &ALLOC_WMARK_MASK ]; + mark =wmark_pages (zone, alloc_flags &ALLOC_WMARK_MASK );if (!zone_watermark_fast (zone, order, mark,ac_classzone_idx (ac), alloc_flags)) {int ret;
@@ -4796,7 +4796,7 @@ long si_mem_available(void) pages[lru] =global_node_page_state (NR_LRU_BASE + lru);for_each_zone (zone) - wmark_low += zone->watermark[WMARK_LOW ]; + wmark_low +=low_wmark_pages (zone);/* * Estimate the amount of memory available for userspace allocations,
@@ -7422,13 +7422,13 @@ static void __setup_per_zone_wmarks(void) min_pages = zone->managed_pages /1024 ; min_pages =clamp (min_pages,SWAP_CLUSTER_MAX ,128UL ); - zone->watermark[WMARK_MIN ] = min_pages; + zone->_watermark[WMARK_MIN ] = min_pages; }else {/* * If it's a lowmem zone, reserve a number of pages * proportionate to the zone's size. */ - zone->watermark[WMARK_MIN ] = tmp; + zone->_watermark[WMARK_MIN ] = tmp; }/*
@@ -7440,8 +7440,8 @@ static void __setup_per_zone_wmarks(void)mult_frac (zone->managed_pages, watermark_scale_factor, 10000)); - zone->watermark[WMARK_LOW ] =min_wmark_pages (zone) + tmp; - zone->watermark[WMARK_HIGH ] =min_wmark_pages (zone) + tmp *2 ; + zone->_watermark[WMARK_LOW ] =min_wmark_pages (zone) + tmp; + zone->_watermark[WMARK_HIGH ] =min_wmark_pages (zone) + tmp *2 ;spin_unlock_irqrestore (&zone->lock, flags); }
Signature · 1 line
2.16.4
PATCH 3/5 mm: Use alloc_flags to record if kswapd can wake
In reply to Mel GormanThis is a preparation patch that copies the GFP flag __GFP_KSWAPD_RECLAIM into alloc_flags. This is a preparation patch only that avoids having to pass gfp_mask through a long callchain in a future patch.
Note that the setting in the fast path happens in alloc_flags_nofragment() and it may be claimed that this has nothing to do with ALLOC_NO_FRAGMENT. That's true in this patch but is not true later so it's done now for easier review to show where the flag needs to be recorded.
No functional change.
--- mm/internal.h | 1 + mm/page_alloc.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-)
mm/internal.h +1 -0
@@ -489,6 +489,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,#else #define ALLOC_NOFRAGMENT 0x0#endif +#define ALLOC_KSWAPD 0x200/* allow waking of kswapd */ enum ttu_flags ;struct tlbflush_unmap_batch ;
mm/page_alloc.c +17 -8
@@ -3278,10 +3278,15 @@ static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)* fragmentation between the Normal and DMA32 zones. */ static inline unsigned int -alloc_flags_nofragment (struct zone *zone) +alloc_flags_nofragment (struct zone *zone,gfp_t gfp_mask) { +unsigned int alloc_flags =0 ; + +if (gfp_mask & __GFP_KSWAPD_RECLAIM) + alloc_flags |=ALLOC_KSWAPD ; +if (zone_idx (zone) !=ZONE_NORMAL ) -return 0 ; + goto out;/* * If ZONE_DMA32 exists, assume it is the one after ZONE_NORMAL and
@@ -3290,13 +3295,14 @@ alloc_flags_nofragment(struct zone *zone)*/ BUILD_BUG_ON (ZONE_NORMAL -ZONE_DMA32 !=1 );if (nr_online_nodes >1 && !populated_zone (--zone)) -return 0 ; + goto out; - return ALLOC_NOFRAGMENT; +out: + return alloc_flags; }#else static inline unsigned int -alloc_flags_nofragment (struct zone *zone) +alloc_flags_nofragment (struct zone *zone,gfp_t gfp_mask) {return 0 ; }
@@ -3939,6 +3945,9 @@ gfp_to_alloc_flags(gfp_t gfp_mask) }else if (unlikely (rt_task (current)) && !in_interrupt ()) alloc_flags |=ALLOC_HARDER ; +if (gfp_mask & __GFP_KSWAPD_RECLAIM) + alloc_flags |=ALLOC_KSWAPD ; +#ifdef CONFIG_CMA if (gfpflags_to_migratetype (gfp_mask) ==MIGRATE_MOVABLE ) alloc_flags |=ALLOC_CMA ;
@@ -4170,7 +4179,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,if (!ac->preferred_zoneref->zone) goto nopage; -if (gfp_mask & __GFP_KSWAPD_RECLAIM) +if (alloc_flags &ALLOC_KSWAPD )wake_all_kswapds (order, gfp_mask, ac);/*
@@ -4228,7 +4237,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, retry:/* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ -if (gfp_mask & __GFP_KSWAPD_RECLAIM) +if (alloc_flags &ALLOC_KSWAPD )wake_all_kswapds (order, gfp_mask, ac); reserve_flags =__gfp_pfmemalloc_flags (gfp_mask);
@@ -4451,7 +4460,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,* Forbid the first pass from falling back to types that fragment * memory until all local zones are considered. */ - alloc_flags |=alloc_flags_nofragment (ac.preferred_zoneref->zone); + alloc_flags |=alloc_flags_nofragment (ac.preferred_zoneref->zone, gfp_mask);/* First allocation attempt */ page =get_page_from_freelist (alloc_mask, order, alloc_flags, &ac);
Signature · 1 line
2.16.4
Re: [PATCH 3/5] mm: Use alloc_flags to record if kswapd can wake
Quoted 4 lines · Mel Gorman
This is a preparation patch that copies the GFP flag
__GFP_KSWAPD_RECLAIMintoalloc_flags. This is a preparation patch only that avoids having to passgfp_maskthrough a long callchain in a future patch.
Quoted 8 lines
Note that the setting in the fast path happens in
alloc_flags_nofragment()and it may be claimed that this has nothing to do withALLOC_NO_FRAGMENT. That's true in this patch but is not true later so it's done now for easier review to show where the flag needs to be recorded.No functional change.
Signed-off-by Mel Gorman <[email protected]>
Small bug below:
Quoted 27 lines
mm/page_alloc.c +8
-3@@ -3278,10 +3278,15 @@ static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)* fragmentation between the Normal and DMA32 zones. */ static inline unsigned int -alloc_flags_nofragment (struct zone *zone) +alloc_flags_nofragment (struct zone *zone,gfp_t gfp_mask) { +unsigned int alloc_flags =0 ; + +if (gfp_mask & __GFP_KSWAPD_RECLAIM) + alloc_flags |=ALLOC_KSWAPD ; +if (zone_idx (zone) !=ZONE_NORMAL ) -return 0 ; + goto out;/* * If ZONE_DMA32 exists, assume it is the one after ZONE_NORMAL and @@ -3290,13 +3295,14 @@ alloc_flags_nofragment(struct zone *zone)*/ BUILD_BUG_ON (ZONE_NORMAL -ZONE_DMA32 !=1 );if (nr_online_nodes >1 && !populated_zone (--zone)) -return 0 ; + goto out;
mm/page_alloc.c alloc_flags_nofragment(struct zone *zone) · line 3307
Quoted 10 lines
mm/page_alloc.c +3
-2- return ALLOC_NOFRAGMENT; +out: + return alloc_flags; }#else static inline unsigned int -alloc_flags_nofragment (struct zone *zone) +alloc_flags_nofragment (struct zone *zone,gfp_t gfp_mask) {return 0 ;
The !CONFIG_ZONE_DMA32 version should still set ALLOC_KSWAPD, right?
Quoted 11 lines
mm/page_alloc.c +3
-0}@@ -3939,6 +3945,9 @@ gfp_to_alloc_flags(gfp_t gfp_mask) }else if (unlikely (rt_task (current)) && !in_interrupt ()) alloc_flags |=ALLOC_HARDER ; +if (gfp_mask & __GFP_KSWAPD_RECLAIM) + alloc_flags |=ALLOC_KSWAPD ; +#ifdef CONFIG_CMA if (gfpflags_to_migratetype (gfp_mask) ==MIGRATE_MOVABLE ) alloc_flags |=ALLOC_CMA ;
PATCH 1/1 mm: Use alloc_flags to record if kswapd can wake -fix
Vlastimil Babka correctly pointed out that the ALLOC_KSWAPD flag needs to be applied in the !CONFIG_ZONE_DMA32 case. This is a fix for the mmotm path mm-use-alloc_flags-to-record-if-kswapd-can-wake.patch
--- mm/page_alloc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
mm/page_alloc.c +2 -8
@@ -3268,7 +3268,6 @@ static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone) }#endif /* CONFIG_NUMA */ -#ifdef CONFIG_ZONE_DMA32 /* * The restriction on ZONE_DMA32 as being a suitable zone to use to avoid * fragmentation is subtle. If the preferred zone was HIGHMEM then
@@ -3285,6 +3284,7 @@ alloc_flags_nofragment(struct zone *zone, gfp_t gfp_mask)if (gfp_mask & __GFP_KSWAPD_RECLAIM) alloc_flags |=ALLOC_KSWAPD ; +#ifdef CONFIG_ZONE_DMA32 if (zone_idx (zone) !=ZONE_NORMAL ) goto out;
@@ -3298,15 +3298,9 @@ alloc_flags_nofragment(struct zone *zone, gfp_t gfp_mask) goto out; out: +#endif /* CONFIG_ZONE_DMA32 */ return alloc_flags; } -#else -static inline unsigned int -alloc_flags_nofragment (struct zone *zone,gfp_t gfp_mask) -{ -return 0 ; -} -#endif /* * get_page_from_freelist goes through the zonelist trying to allocate
PATCH 4/5 mm: Reclaim small amounts of memory when an external fragmentation event occurs
In reply to Mel GormanAn external fragmentation event was previously described as
When the page allocator fragments memory, it records the event using the mm_page_alloc_extfrag event. If the fallback_order is smaller than a pageblock order (order-9 on 64-bit x86) then it's considered an event that will cause external fragmentation issues in the future.
The kernel reduces the probability of such events by increasing the watermark sizes by calling set_recommended_min_free_kbytes early in the lifetime of the system. This works reasonably well in general but if there are enough sparsely populated pageblocks then the problem can still occur as enough memory is free overall and kswapd stays asleep.
This patch introduces a watermark_boost_factor sysctl that allows a zone watermark to be temporarily boosted when an external fragmentation causing events occurs. The boosting will stall allocations that would decrease free memory below the boosted low watermark and kswapd is woken if the calling context allows to reclaim an amount of memory relative to the size of the high watermark and the watermark_boost_factor until the boost is cleared. When kswapd finishes, it wakes kcompactd at the pageblock order to clean some of the pageblocks that may have been affected by the fragmentation event. kswapd avoids any writeback, slab shrinkage and swap from reclaim context during this operation to avoid excessive system disruption in the name of fragmentation avoidance. Care is taken so that kswapd will do normal reclaim work if the system is really low on memory.
This was evaluated using the same workloads as "mm, page_alloc: Spread allocations across zones before introducing fragmentation".
1-socket Skylake machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 1 THP allocating thread
--------------------------------------
4.20-rc3 extfrag events < order 9: 804694
4.20-rc3+patch: 408912 (49% reduction)
4.20-rc3+patch1-4: 18421 (98% reduction)
4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8
Amean fault-base-1 653.58 ( 0.00%) 652.71 ( 0.13%)
Amean fault-huge-1 0.00 ( 0.00%) 178.93 * -99.00%* 4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8Percentage huge-1 0.00 ( 0.00%) 5.12 ( 100.00%)
Note that external fragmentation causing events are massively reduced by this path whether in comparison to the previous kernel or the vanilla kernel. The fault latency for huge pages appears to be increased but that is only because THP allocations were successful with the patch applied.
1-socket Skylake machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 291392
4.20-rc3+patch: 191187 (34% reduction)
4.20-rc3+patch1-4: 13464 (95% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8
Min fault-base-1 912.00 ( 0.00%) 905.00 ( 0.77%)
Min fault-huge-1 127.00 ( 0.00%) 135.00 ( -6.30%)
Amean fault-base-1 1467.55 ( 0.00%) 1481.67 ( -0.96%)
Amean fault-huge-1 1127.11 ( 0.00%) 1063.88 * 5.61%* 4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8Percentage huge-1 77.64 ( 0.00%) 83.46 ( 7.49%)
As before, massive reduction in external fragmentation events, some jitter on latencies and an increase in THP allocation success rates.
2-socket Haswell machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 5 THP allocating threads
----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 215698
4.20-rc3+patch: 200210 (7% reduction)
4.20-rc3+patch1-4: 14263 (93% reduction)
4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8
Amean fault-base-5 1346.45 ( 0.00%) 1306.87 ( 2.94%)
Amean fault-huge-5 3418.60 ( 0.00%) 1348.94 ( 60.54%) 4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8Percentage huge-5 0.78 ( 0.00%) 7.91 ( 910.64%)
There is a 93% reduction in fragmentation causing events, there is a big reduction in the huge page fault latency and allocation success rate is higher.
2-socket Haswell machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 166352
4.20-rc3+patch: 147463 (11% reduction)
4.20-rc3+patch1-4: 11095 (93% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8
Amean fault-base-5 6217.43 ( 0.00%) 7419.67 * -19.34%*
Amean fault-huge-5 3163.33 ( 0.00%) 3263.80 ( -3.18%) 4.20.0-rc3 4.20.0-rc3
lowzone-v5r8 boost-v5r8Percentage huge-5 95.14 ( 0.00%) 87.98 ( -7.53%)
There is a large reduction in fragmentation events with some jitter around the latencies and success rates. As before, the high THP allocation success rate does mean the system is under a lot of pressure. However, as the fragmentation events are reduced, it would be expected that the long-term allocation success rate would be higher.
--- Documentation/sysctl/vm.txt | 21 +++++++ include/linux/mm.h | 1 + include/linux/mmzone.h | 11 ++-- kernel/sysctl.c | 8 +++ mm/page_alloc.c | 43 +++++++++++++- mm/vmscan.c | 133 +++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 202 insertions(+), 15 deletions(-)
Documentation/sysctl/vm.txt +21 -0
@@ -63,6 +63,7 @@ files can be found in mm/swap.c. - swappiness - user_reserve_kbytes - vfs_cache_pressure +- watermark_boost_factor - watermark_scale_factor - zone_reclaim_mode
@@ -856,6 +857,26 @@ ten times more freeable objects than there are. ============================================================= +watermark_boost_factor: + +This factor controls the level of reclaim when memory is being fragmented. +It defines the percentage of the high watermark of a zone that will be +reclaimed if pages of different mobility are being mixed within pageblocks. +The intent is that compaction has less work to do in the future and to +increase the success rate of future high-order allocations such as SLUB +allocations, THP and hugetlbfs pages. + +To make it sensible with respect to the watermark_scale_factor parameter, +the unit is in fractions of 10,000. The default value of 15,000 means +that up to 150% of the high watermark will be reclaimed in the event of +a pageblock being mixed due to fragmentation. The level of reclaim is +determined by the number of fragmentation events that occurred in the +recent past. If this value is smaller than a pageblock then a pageblocks +worth of pages will be reclaimed (e.g. 2MB on 64-bit x86). A boost factor +of 0 will disable the feature. + +============================================================= + watermark_scale_factor: This factor controls the aggressiveness of kswapd. It defines the
include/linux/mm.h +1 -0
@@ -2202,6 +2202,7 @@ extern void zone_pcp_reset(struct zone *zone);/* page_alloc.c */ extern int min_free_kbytes; +extern int watermark_boost_factor;extern int watermark_scale_factor;/* nommu.c */
include/linux/mmzone.h +7 -4
@@ -269,10 +269,10 @@ enum zone_watermarks {NR_WMARK }; -#define min_wmark_pages (z) (z->_watermark[WMARK_MIN]) -#define low_wmark_pages (z) (z->_watermark[WMARK_LOW]) -#define high_wmark_pages (z) (z->_watermark[WMARK_HIGH]) -#define wmark_pages (z, i) (z->_watermark[i]) +#define min_wmark_pages (z) (z->_watermark[WMARK_MIN] + z->watermark_boost) +#define low_wmark_pages (z) (z->_watermark[WMARK_LOW] + z->watermark_boost) +#define high_wmark_pages (z) (z->_watermark[WMARK_HIGH] + z->watermark_boost) +#define wmark_pages (z, i) (z->_watermark[i] + z->watermark_boost)struct per_cpu_pages {int count;/* number of pages in the list */
@@ -364,6 +364,7 @@ struct zone {/* zone watermarks, access with *_wmark_pages(zone) macros */ unsigned long _watermark[NR_WMARK ]; +unsigned long watermark_boost;unsigned long nr_reserved_highatomic;
@@ -885,6 +886,8 @@ static inline int is_highmem(struct zone *zone)struct ctl_table ;int min_free_kbytes_sysctl_handler (struct ctl_table *,int ,void __user *,size_t *,loff_t *); +int watermark_boost_factor_sysctl_handler (struct ctl_table *,int , +void __user *,size_t *,loff_t *);int watermark_scale_factor_sysctl_handler (struct ctl_table *,int ,void __user *,size_t *,loff_t *);extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES ];
kernel/sysctl.c +8 -0
@@ -1462,6 +1462,14 @@ static struct ctl_table vm_table[] = { .proc_handler = min_free_kbytes_sysctl_handler, .extra1 = &zero, }, + { + .procname = "watermark_boost_factor", + .data = &watermark_boost_factor, + .maxlen = sizeof(watermark_boost_factor), + .mode = 0644, + .proc_handler = watermark_boost_factor_sysctl_handler, + .extra1 = &zero, + }, { .procname = "watermark_scale_factor", .data = &watermark_scale_factor,
mm/page_alloc.c +41 -2
85 lines not on this page · raw message
mm/vmscan.c +124 -9
223 lines not on this page · raw message
Signature · 1 line
2.16.4
Re: [PATCH 4/5] mm: Reclaim small amounts of memory when an external fragmentation event occurs
Quoted 115 lines · Mel Gorman
An external fragmentation event was previously described as
When the page allocator fragments memory, it records the event using the
mm_page_alloc_extfragevent. If thefallback_orderis smaller than a pageblock order (order-9 on 64-bit x86) then it's considered an event that will cause external fragmentation issues in the future.The kernel reduces the probability of such events by increasing the watermark sizes by calling
set_recommended_min_free_kbytesearly in the lifetime of the system. This works reasonably well in general but if there are enough sparsely populated pageblocks then the problem can still occur as enough memory is free overall and kswapd stays asleep.This patch introduces a
watermark_boost_factorsysctl that allows a zone watermark to be temporarily boosted when an external fragmentation causing events occurs. The boosting will stall allocations that would decrease free memory below the boosted low watermark and kswapd is woken if the calling context allows to reclaim an amount of memory relative to the size of the high watermark and thewatermark_boost_factoruntil the boost is cleared. When kswapd finishes, it wakes kcompactd at the pageblock order to clean some of the pageblocks that may have been affected by the fragmentation event. kswapd avoids any writeback, slab shrinkage and swap from reclaim context during this operation to avoid excessive system disruption in the name of fragmentation avoidance. Care is taken so that kswapd will do normal reclaim work if the system is really low on memory.This was evaluated using the same workloads as "mm,
page_alloc: Spread allocations across zones before introducing fragmentation".1-socket Skylake machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 1 THP allocating thread
--------------------------------------4.20-rc3 extfrag events < order 9: 804694
4.20-rc3+patch: 408912 (49% reduction)
4.20-rc3+patch1-4: 18421 (98% reduction)4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8 Amean fault-base-1 653.58 ( 0.00%) 652.71 ( 0.13%) Amean fault-huge-1 0.00 ( 0.00%) 178.93 * -99.00%*4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8Percentage huge-1 0.00 ( 0.00%) 5.12 ( 100.00%)
Note that external fragmentation causing events are massively reduced by this path whether in comparison to the previous kernel or the vanilla kernel. The fault latency for huge pages appears to be increased but that is only because THP allocations were successful with the patch applied.
1-socket Skylake machine global-dhp__workload_thpfioscale-madvhugepage-xfs (
MADV_HUGEPAGE)
-----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 291392
4.20-rc3+patch: 191187 (34% reduction)
4.20-rc3+patch1-4: 13464 (95% reduction)thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8 Min fault-base-1 912.00 ( 0.00%) 905.00 ( 0.77%) Min fault-huge-1 127.00 ( 0.00%) 135.00 ( -6.30%) Amean fault-base-1 1467.55 ( 0.00%) 1481.67 ( -0.96%) Amean fault-huge-1 1127.11 ( 0.00%) 1063.88 * 5.61%*4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8Percentage huge-1 77.64 ( 0.00%) 83.46 ( 7.49%)
As before, massive reduction in external fragmentation events, some jitter on latencies and an increase in THP allocation success rates.
2-socket Haswell machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 5 THP allocating threads
----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 215698
4.20-rc3+patch: 200210 (7% reduction)
4.20-rc3+patch1-4: 14263 (93% reduction)4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8 Amean fault-base-5 1346.45 ( 0.00%) 1306.87 ( 2.94%) Amean fault-huge-5 3418.60 ( 0.00%) 1348.94 ( 60.54%)4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8Percentage huge-5 0.78 ( 0.00%) 7.91 ( 910.64%)
There is a 93% reduction in fragmentation causing events, there is a big reduction in the huge page fault latency and allocation success rate is higher.
2-socket Haswell machine global-dhp__workload_thpfioscale-madvhugepage-xfs (
MADV_HUGEPAGE)
-----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 166352
4.20-rc3+patch: 147463 (11% reduction)
4.20-rc3+patch1-4: 11095 (93% reduction)thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8 Amean fault-base-5 6217.43 ( 0.00%) 7419.67 * -19.34%* Amean fault-huge-5 3163.33 ( 0.00%) 3263.80 ( -3.18%)4.20.0-rc3 4.20.0-rc3 lowzone-v5r8 boost-v5r8Percentage huge-5 95.14 ( 0.00%) 87.98 ( -7.53%)
Quoted 7 lines
There is a large reduction in fragmentation events with some jitter around the latencies and success rates. As before, the high THP allocation success rate does mean the system is under a lot of pressure. However, as the fragmentation events are reduced, it would be expected that the long-term allocation success rate would be higher.
Signed-off-by Mel Gorman <[email protected]>
PATCH 5/5 mm: Stall movable allocations until kswapd progresses during serious external fragmentation event
In reply to Mel GormanAn event that potentially causes external fragmentation problems has already been described but there are degrees of severity. A "serious" event is defined as one that steals a contiguous range of pages of an order lower than fragment_stall_order (PAGE_ALLOC_COSTLY_ORDER by default). If a movable allocation request that is allowed to sleep needs to steal a small block then it schedules until kswapd makes progress or a timeout passes. The watermarks are also boosted slightly faster so that kswapd makes greater effort to reclaim enough pages to avoid the fragmentation event.
This stall is not guaranteed to avoid serious fragmentation events. If memory pressure is high enough, the pages freed by kswapd may be reallocated or the free pages may not be in pageblocks that contain only movable pages. Furthermore an allocation request that cannot stall (e.g. atomic allocations) or unmovable/reclaimable allocations will still proceed without stalling. The reason is that movable allocations can be migrated and stalling for kswapd to make progress means that compaction has targets. Unmovable/reclaimable allocations on the other hand do not benefit from stalling as their pages cannot move.
The worst-case scenario for stalling is a combination of both high memory pressure where kswapd is having trouble keeping free pages over the pfmemalloc_reserve and movable allocations are fragmenting memory. In this case, an allocation request may sleep for longer. There are both vmstats to identify stalls are happening and a tracepoint to quantify what the stall durations are. Note that the granularity of the stall detection is a jiffy so the delay accounting is not precise.
1-socket Skylake machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 1 THP allocating thread
--------------------------------------
4.20-rc3 extfrag events < order 9: 804694
4.20-rc3+patch: 408912 (49% reduction)
4.20-rc3+patch1-4: 18421 (98% reduction)
4.20-rc3+patch1-5: 16788 (98% reduction)
4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8
Amean fault-base-1 652.71 ( 0.00%) 651.40 ( 0.20%)
Amean fault-huge-1 178.93 ( 0.00%) 174.49 * 2.48%*thpfioscale Percentage Faults Huge
4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8Percentage huge-1 5.12 ( 0.00%) 5.56 ( 8.77%)
Fragmentation events are further reduced. Note that in previous versions, it was reduced to negligible levels but the logic has been corrected to avoid exceessive reclaim and slab shrinkage in the meantime to avoid IO regressions that may not be tolerable.
The latencies and allocation success rates are roughly similar. Over the course of 16 minutes, there were 2 stalls due to fragmentation avoidance for 8 microseconds.
1-socket Skylake machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 291392
4.20-rc3+patch: 191187 (34% reduction)
4.20-rc3+patch1-4: 13464 (95% reduction)
4.20-rc3+patch1-5: 15089 (99.7% reduction)
4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8
Amean fault-base-1 1481.67 ( 0.00%) 0.00 * 100.00%*
Amean fault-huge-1 1063.88 ( 0.00%) 540.81 * 49.17%* 4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8Percentage huge-1 83.46 ( 0.00%) 100.00 ( 19.82%)
The fragmentation events were increased which is bad, but this is offset by the fact that THP allocation rates had a lower latency and a perfect allocation success rate. There were 102 stalls over the course of 16 minutes for a total stall time of roughly 0.4 seconds.
2-socket Haswell machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 5 THP allocating threads
----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 215698
4.20-rc3+patch: 200210 (7% reduction)
4.20-rc3+patch1-4: 14263 (93% reduction)
4.20-rc3+patch1-5: 11702 (95% reduction)
4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8
Amean fault-base-5 1306.87 ( 0.00%) 1340.96 ( -2.61%)
Amean fault-huge-5 1348.94 ( 0.00%) 2089.44 ( -54.89%) 4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8Percentage huge-5 7.91 ( 0.00%) 2.43 ( -69.26%)
There is a slight reduction in fragmentation events but it's slight enough that it may be due to luck. Unfortunately, both the latencies and success rates were lower. However, this is highly likely to be due to luck given that there were just 12 stalls for 76 microseconds. Direct reclaim was also eliminated but that is likely a co-incidence.
2-socket Haswell machine global-dhp__workload_thpfioscale-madvhugepage-xfs (MADV_HUGEPAGE)
-----------------------------------------------------------------
4.20-rc3 extfrag events < order 9: 166352
4.20-rc3+patch: 147463 (11% reduction)
4.20-rc3+patch1-4: 11095 (93% reduction)
4.20-rc3+patch1-5: 10677 (94% reduction)
thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8
Amean fault-base-5 7419.67 ( 0.00%) 6853.97 ( 7.62%)
Amean fault-huge-5 3263.80 ( 0.00%) 1799.26 * 44.87%* 4.20.0-rc3 4.20.0-rc3
boost-v5r8 stall-v5r8Percentage huge-5 87.98 ( 0.00%) 98.97 ( 12.49%)
The fragmentation events are slightly reduced with the latencies and allocation success rates much improved. There were 462 stalls over the course of 68 minutes with a total stall time of roughly 1.9 seconds.
This patch has a marginal rate on fragmentation rates as it's rare for the stall logic to actually trigger but the small stalls can be enough for kswapd to catch up. How much that helps is variable but probably worthwhile for long-term allocation success rates. It is possible to eliminate fragmentation events entirely with tuning due to this patch although that would require careful evaluation to determine if it's worthwhile.
--- Documentation/sysctl/vm.txt | 23 +++++++++ include/linux/mm.h | 1 + include/linux/mmzone.h | 2 + include/linux/vm_event_item.h | 1 + include/trace/events/kmem.h | 21 +++++++++ kernel/sysctl.c | 10 ++++ mm/internal.h | 1 + mm/page_alloc.c | 105 +++++++++++++++++++++++++++++++++++++----- mm/vmscan.c | 3 +- mm/vmstat.c | 1 + 10 files changed, 155 insertions(+), 13 deletions(-)
Documentation/sysctl/vm.txt +23 -0
@@ -31,6 +31,7 @@ files can be found in mm/swap.c. - dirty_writeback_centisecs - drop_caches - extfrag_threshold +- fragment_stall_order - hugetlb_shm_group - laptop_mode - legacy_va_layout
@@ -275,6 +276,28 @@ any throttling. ============================================================== +fragment_stall_order + +External fragmentation control is managed on a pageblock level where the +page allocator tries to avoid mixing pages of different mobility within page +blocks (e.g. order 9 on 64-bit x86). If external fragmentation is perfectly +controlled then a THP allocation will often succeed up to the number of +movable pageblocks in the system as reported by /proc/pagetypeinfo. + +When memory is low, the system may have to mix pageblocks and will wake +kswapd to try control future fragmentation. fragment_stall_order controls if +the allocating task will stall if possible until kswapd makes some progress +in preference to fragmenting the system. This incurs a small stall penalty +in exchange for future success at allocating huge pages. If the stalls +are undesirable and high-order allocations are irrelevant then this can +be disabled by writing 0 to the tunable. Writing the pageblock order will +strongly (but not perfectly) control external fragmentation. + +The default (4) will stall for fragmenting allocations less than or equal +to the PAGE_ALLOC_COSTLY_ORDER (defined as order-3 at the time of writing). + +============================================================== + hugetlb_shm_group hugetlb_shm_group contains group id that is allowed to create SysV
include/linux/mm.h +1 -0
@@ -2204,6 +2204,7 @@ extern void zone_pcp_reset(struct zone *zone);extern int min_free_kbytes;extern int watermark_boost_factor;extern int watermark_scale_factor; +extern int fragment_stall_order;/* nommu.c */ extern atomic_long_t mmap_pages_allocated;
include/linux/mmzone.h +2 -0
@@ -890,6 +890,8 @@ int watermark_boost_factor_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *);int watermark_scale_factor_sysctl_handler (struct ctl_table *,int ,void __user *,size_t *,loff_t *); +int fragment_stall_order_sysctl_handler (struct ctl_table *,int , +void __user *,size_t *,loff_t *);extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES ];int lowmem_reserve_ratio_sysctl_handler (struct ctl_table *,int ,void __user *,size_t *,loff_t *);
include/linux/vm_event_item.h +1 -0
@@ -43,6 +43,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,PAGEOUTRUN ,PGROTATED ,DROP_PAGECACHE ,DROP_SLAB ,OOM_KILL , +FRAGMENTSTALL , #ifdef CONFIG_NUMA_BALANCINGNUMA_PTE_UPDATES , NUMA_HUGE_PTE_UPDATES,
include/trace/events/kmem.h +21 -0
@@ -315,6 +315,27 @@ TRACE_EVENT(mm_page_alloc_extfrag, __entry->change_ownership) ); +TRACE_EVENT (mm_fragmentation_stall, + + TP_PROTO(int nid, unsigned long duration), + +TP_ARGS (nid, duration), + +TP_STRUCT__entry ( + __field( int, nid ) + __field( unsigned long, duration ) + ), + +TP_fast_assign ( + __entry->nid = nid; + __entry->duration = duration + ), + +TP_printk ("nid=%d duration=%lu" , + __entry->nid, + __entry->duration) +); +#endif /* _TRACE_KMEM_H */ /* This part must be outside protection */
kernel/sysctl.c +10 -0
@@ -126,6 +126,7 @@ static int zero;static int __maybe_unused one =1 ;static int __maybe_unused two =2 ;static int __maybe_unused four =4 ; +static int __maybe_unused max_order =MAX_ORDER ;static unsigned long one_ul =1 ;static int one_hundred =100 ;static int one_thousand =1000 ;
@@ -1479,6 +1480,15 @@ static struct ctl_table vm_table[] = { .extra1 = &one, .extra2 = &one_thousand, }, + { + .procname = "fragment_stall_order", + .data = &fragment_stall_order, + .maxlen = sizeof(fragment_stall_order), + .mode = 0644, + .proc_handler = fragment_stall_order_sysctl_handler, + .extra1 = &zero, + .extra2 = &max_order, + }, { .procname = "percpu_pagelist_fraction", .data = &percpu_pagelist_fraction,
mm/internal.h +1 -0
@@ -490,6 +490,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,#define ALLOC_NOFRAGMENT 0x0#endif #define ALLOC_KSWAPD 0x200/* allow waking of kswapd */ +#define ALLOC_FRAGMENT_STALL 0x400/* stall if fragmenting heavily */ enum ttu_flags ;struct tlbflush_unmap_batch ;
mm/page_alloc.c +93 -12
217 lines not on this page · raw message
mm/vmscan.c +2 -1
@@ -3685,7 +3685,8 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)* able to safely make forward progress. Wake them */ if (waitqueue_active (&pgdat->pfmemalloc_wait) && -allow_direct_reclaim (pgdat)) + ((!raise_priority && nr_boost_reclaim) || +allow_direct_reclaim (pgdat)))wake_up_all (&pgdat->pfmemalloc_wait);/* Check if kswapd should be suspending */
mm/vmstat.c +1 -0
@@ -1211,6 +1211,7 @@ const char * const vmstat_text[] = {"drop_pagecache" ,"drop_slab" ,"oom_kill" , +"fragment_stall" , #ifdef CONFIG_NUMA_BALANCING "numa_pte_updates",
Signature · 1 line
2.16.4
Re: [PATCH 5/5] mm: Stall movable allocations until kswapd progresses during serious external fragmentation event
Quoted 127 lines · Mel Gorman
An event that potentially causes external fragmentation problems has already been described but there are degrees of severity. A "serious" event is defined as one that steals a contiguous range of pages of an order lower than
fragment_stall_order(PAGE_ALLOC_COSTLY_ORDERby default). If a movable allocation request that is allowed to sleep needs to steal a small block then it schedules until kswapd makes progress or a timeout passes. The watermarks are also boosted slightly faster so that kswapd makes greater effort to reclaim enough pages to avoid the fragmentation event.This stall is not guaranteed to avoid serious fragmentation events. If memory pressure is high enough, the pages freed by kswapd may be reallocated or the free pages may not be in pageblocks that contain only movable pages. Furthermore an allocation request that cannot stall (e.g. atomic allocations) or unmovable/reclaimable allocations will still proceed without stalling. The reason is that movable allocations can be migrated and stalling for kswapd to make progress means that compaction has targets. Unmovable/reclaimable allocations on the other hand do not benefit from stalling as their pages cannot move.
The worst-case scenario for stalling is a combination of both high memory pressure where kswapd is having trouble keeping free pages over the
pfmemalloc_reserveand movable allocations are fragmenting memory. In this case, an allocation request may sleep for longer. There are both vmstats to identify stalls are happening and a tracepoint to quantify what the stall durations are. Note that the granularity of the stall detection is a jiffy so the delay accounting is not precise.1-socket Skylake machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 1 THP allocating thread
--------------------------------------4.20-rc3 extfrag events < order 9: 804694
4.20-rc3+patch: 408912 (49% reduction)
4.20-rc3+patch1-4: 18421 (98% reduction)
4.20-rc3+patch1-5: 16788 (98% reduction)4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8 Amean fault-base-1 652.71 ( 0.00%) 651.40 ( 0.20%) Amean fault-huge-1 178.93 ( 0.00%) 174.49 * 2.48%*thpfioscale Percentage Faults Huge
4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8Percentage huge-1 5.12 ( 0.00%) 5.56 ( 8.77%)
Fragmentation events are further reduced. Note that in previous versions, it was reduced to negligible levels but the logic has been corrected to avoid exceessive reclaim and slab shrinkage in the meantime to avoid IO regressions that may not be tolerable.
The latencies and allocation success rates are roughly similar. Over the course of 16 minutes, there were 2 stalls due to fragmentation avoidance for 8 microseconds.
1-socket Skylake machine global-dhp__workload_thpfioscale-madvhugepage-xfs (
MADV_HUGEPAGE)
-----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 291392
4.20-rc3+patch: 191187 (34% reduction)
4.20-rc3+patch1-4: 13464 (95% reduction)
4.20-rc3+patch1-5: 15089 (99.7% reduction)4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8 Amean fault-base-1 1481.67 ( 0.00%) 0.00 * 100.00%* Amean fault-huge-1 1063.88 ( 0.00%) 540.81 * 49.17%*4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8Percentage huge-1 83.46 ( 0.00%) 100.00 ( 19.82%)
The fragmentation events were increased which is bad, but this is offset by the fact that THP allocation rates had a lower latency and a perfect allocation success rate. There were 102 stalls over the course of 16 minutes for a total stall time of roughly 0.4 seconds.
2-socket Haswell machine config-global-dhp__workload_thpfioscale XFS (no special madvise) 4 fio threads, 5 THP allocating threads
----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 215698
4.20-rc3+patch: 200210 (7% reduction)
4.20-rc3+patch1-4: 14263 (93% reduction)
4.20-rc3+patch1-5: 11702 (95% reduction)4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8 Amean fault-base-5 1306.87 ( 0.00%) 1340.96 ( -2.61%) Amean fault-huge-5 1348.94 ( 0.00%) 2089.44 ( -54.89%)4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8Percentage huge-5 7.91 ( 0.00%) 2.43 ( -69.26%)
There is a slight reduction in fragmentation events but it's slight enough that it may be due to luck. Unfortunately, both the latencies and success rates were lower. However, this is highly likely to be due to luck given that there were just 12 stalls for 76 microseconds. Direct reclaim was also eliminated but that is likely a co-incidence.
2-socket Haswell machine global-dhp__workload_thpfioscale-madvhugepage-xfs (
MADV_HUGEPAGE)
-----------------------------------------------------------------4.20-rc3 extfrag events < order 9: 166352
4.20-rc3+patch: 147463 (11% reduction)
4.20-rc3+patch1-4: 11095 (93% reduction)
4.20-rc3+patch1-5: 10677 (94% reduction)thpfioscale Fault Latencies
4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8 Amean fault-base-5 7419.67 ( 0.00%) 6853.97 ( 7.62%) Amean fault-huge-5 3263.80 ( 0.00%) 1799.26 * 44.87%*4.20.0-rc3 4.20.0-rc3 boost-v5r8 stall-v5r8Percentage huge-5 87.98 ( 0.00%) 98.97 ( 12.49%)
The fragmentation events are slightly reduced with the latencies and allocation success rates much improved. There were 462 stalls over the course of 68 minutes with a total stall time of roughly 1.9 seconds.
Quoted 8 lines
This patch has a marginal rate on fragmentation rates as it's rare for the stall logic to actually trigger but the small stalls can be enough for kswapd to catch up. How much that helps is variable but probably worthwhile for long-term allocation success rates. It is possible to eliminate fragmentation events entirely with tuning due to this patch although that would require careful evaluation to determine if it's worthwhile.
Signed-off-by Mel Gorman <[email protected]>
The gains here are relatively smaller and noisier than for the previous patches. Also I'm afraid that once antifrag loses against the ultimate adversary workload (see the "Caching/buffers become useless after some time" thread), then this might result in adding stalls to a workload that has no other options but to allocate movable pages from partially filled unmovable blocks, because that's simply the majority of pageblocks in the system, and the stalls can't help the situation. If that proves to be true, we could revert, but then there's the new user-visible tunable... and that all makes it harder for me to decide about this patch :) If only we could find out early while this is in linux-mm/linux-next...
Re: [PATCH 5/5] mm: Stall movable allocations until kswapd progresses during serious external fragmentation event
Quoted 11 lines · Vlastimil Babka
Quoted 8 lines
This patch has a marginal rate on fragmentation rates as it's rare for the stall logic to actually trigger but the small stalls can be enough for kswapd to catch up. How much that helps is variable but probably worthwhile for long-term allocation success rates. It is possible to eliminate fragmentation events entirely with tuning due to this patch although that would require careful evaluation to determine if it's worthwhile.
Signed-off-by Mel Gorman <[email protected]>The gains here are relatively smaller and noisier than for the previous patches.
Indeed, in an earlier illogical version then it had a bigger impact but that was due to buggy side-effects.
Quoted 11 lines
Also I'm afraid that once antifrag loses against the ultimate adversary workload (see the "Caching/buffers become useless after some time" thread), then this might result in adding stalls to a workload that has no other options but to allocate movable pages from partially filled unmovable blocks, because that's simply the majority of pageblocks in the system, and the stalls can't help the situation. If that proves to be true, we could revert, but then there's the new user-visible tunable... and that all makes it harder for me to decide about this patch :) If only we could find out early while this is in linux-mm/linux-next...
I think in the event it has to revert that it would be ok for the tuning to disappear at the same time. There are occasions where a particular tuning has side-effects that make it harder to remove the interface but in this case, the tuning is directly related to the patch itself.
That said, stalling behaviour has been problematic so if we want to play it safe then I do not mind this patch being dropped until there is a definite benefit from it as the bulk of the series benefit is from the first 4 patches.
Signature · 2 lines
Mel Gorman SUSE Labs
Re: [PATCH 5/5] mm: Stall movable allocations until kswapd progresses during serious external fragmentation event
In reply to Vlastimil BabkaQuoted 9 lines · Vlastimil Babka
Quoted 8 lines
This patch has a marginal rate on fragmentation rates as it's rare for the stall logic to actually trigger but the small stalls can be enough for kswapd to catch up. How much that helps is variable but probably worthwhile for long-term allocation success rates. It is possible to eliminate fragmentation events entirely with tuning due to this patch although that would require careful evaluation to determine if it's worthwhile.
Signed-off-by Mel Gorman <[email protected]>
Quoted 12 lines
The gains here are relatively smaller and noisier than for the previous patches. Also I'm afraid that once antifrag loses against the ultimate adversary workload (see the "Caching/buffers become useless after some time" thread), then this might result in adding stalls to a workload that has no other options but to allocate movable pages from partially filled unmovable blocks, because that's simply the majority of pageblocks in the system, and the stalls can't help the situation. If that proves to be true, we could revert, but then there's the new user-visible tunable... and that all makes it harder for me to decide about this patch :) If only we could find out early while this is in linux-mm/linux-next...
Andrew, would you mind dropping this patch from mmotm please? I think the benefit is marginal relative to the potential loss. If it turns out we ever really do need it then hopefully there will be better data supporting it.
Thanks.
Signature · 2 lines
Mel Gorman SUSE Labs