aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlastimil Babka <vbabka@suse.cz>2016-10-07 19:57:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 21:46:27 -0400
commit06ed29989f39f5129d4f76f4a2d7ce2efa46a6a1 (patch)
tree49e8b10ca708e72762714dfa3d2d1bc435ab9f9a
parent5870c2e1d78b043b69de3199469c056ca3b05102 (diff)
mm, compaction: make whole_zone flag ignore cached scanner positions
Patch series "make direct compaction more deterministic") This is mostly a followup to Michal's oom detection rework, which highlighted the need for direct compaction to provide better feedback in reclaim/compaction loop, so that it can reliably recognize when compaction cannot make further progress, and allocation should invoke OOM killer or fail. We've discussed this at LSF/MM [1] where I proposed expanding the async/sync migration mode used in compaction to more general "priorities". This patchset adds one new priority that just overrides all the heuristics and makes compaction fully scan all zones. I don't currently think that we need more fine-grained priorities, but we'll see. Other than that there's some smaller fixes and cleanups, mainly related to the THP-specific hacks. I've tested this with stress-highalloc in GFP_KERNEL order-4 and THP-like order-9 scenarios. There's some improvement for compaction stats for the order-4, which is likely due to the better watermarks handling. In the previous version I reported mostly noise wrt compaction stats, and decreased direct reclaim - now the reclaim is without difference. I believe this is due to the less aggressive compaction priority increase in patch 6. "before" is a mmotm tree prior to 4.7 release plus the first part of the series that was sent and merged separately before after order-4: Compaction stalls 27216 30759 Compaction success 19598 25475 Compaction failures 7617 5283 Page migrate success 370510 464919 Page migrate failure 25712 27987 Compaction pages isolated 849601 1041581 Compaction migrate scanned 143146541 101084990 Compaction free scanned 208355124 144863510 Compaction cost 1403 1210 order-9: Compaction stalls 7311 7401 Compaction success 1634 1683 Compaction failures 5677 5718 Page migrate success 194657 183988 Page migrate failure 4753 4170 Compaction pages isolated 498790 456130 Compaction migrate scanned 565371 524174 Compaction free scanned 4230296 4250744 Compaction cost 215 203 [1] https://lwn.net/Articles/684611/ This patch (of 11): A recent patch has added whole_zone flag that compaction sets when scanning starts from the zone boundary, in order to report that zone has been fully scanned in one attempt. For allocations that want to try really hard or cannot fail, we will want to introduce a mode where scanning whole zone is guaranteed regardless of the cached positions. This patch reuses the whole_zone flag in a way that if it's already passed true to compaction, the cached scanner positions are ignored. Employing this flag during reclaim/compaction loop will be done in the next patch. This patch however converts compaction invoked from userspace via procfs to use this flag. Before this patch, the cached positions were first reset to zone boundaries and then read back from struct zone, so there was a window where a parallel compaction could replace the reset values, making the manual compaction less effective. Using the flag instead of performing reset is more robust. [akpm@linux-foundation.org: coding-style fixes] Link: http://lkml.kernel.org/r/20160810091226.6709-2-vbabka@suse.cz Signed-off-by: Vlastimil Babka <vbabka@suse.cz> Tested-by: Lorenzo Stoakes <lstoakes@gmail.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: David Rientjes <rientjes@google.com> Cc: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/compaction.c43
-rw-r--r--mm/internal.h2
2 files changed, 22 insertions, 23 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index 9affb2908304..c684ca141e4b 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -1492,23 +1492,29 @@ static enum compact_result compact_zone(struct zone *zone, struct compact_contro
1492 1492
1493 /* 1493 /*
1494 * Setup to move all movable pages to the end of the zone. Used cached 1494 * Setup to move all movable pages to the end of the zone. Used cached
1495 * information on where the scanners should start but check that it 1495 * information on where the scanners should start (unless we explicitly
1496 * is initialised by ensuring the values are within zone boundaries. 1496 * want to compact the whole zone), but check that it is initialised
1497 * by ensuring the values are within zone boundaries.
1497 */ 1498 */
1498 cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync]; 1499 if (cc->whole_zone) {
1499 cc->free_pfn = zone->compact_cached_free_pfn;
1500 if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
1501 cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
1502 zone->compact_cached_free_pfn = cc->free_pfn;
1503 }
1504 if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
1505 cc->migrate_pfn = start_pfn; 1500 cc->migrate_pfn = start_pfn;
1506 zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn; 1501 cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
1507 zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn; 1502 } else {
1508 } 1503 cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync];
1504 cc->free_pfn = zone->compact_cached_free_pfn;
1505 if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) {
1506 cc->free_pfn = pageblock_start_pfn(end_pfn - 1);
1507 zone->compact_cached_free_pfn = cc->free_pfn;
1508 }
1509 if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) {
1510 cc->migrate_pfn = start_pfn;
1511 zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn;
1512 zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
1513 }
1509 1514
1510 if (cc->migrate_pfn == start_pfn) 1515 if (cc->migrate_pfn == start_pfn)
1511 cc->whole_zone = true; 1516 cc->whole_zone = true;
1517 }
1512 1518
1513 cc->last_migrated_pfn = 0; 1519 cc->last_migrated_pfn = 0;
1514 1520
@@ -1747,14 +1753,6 @@ static void __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
1747 INIT_LIST_HEAD(&cc->freepages); 1753 INIT_LIST_HEAD(&cc->freepages);
1748 INIT_LIST_HEAD(&cc->migratepages); 1754 INIT_LIST_HEAD(&cc->migratepages);
1749 1755
1750 /*
1751 * When called via /proc/sys/vm/compact_memory
1752 * this makes sure we compact the whole zone regardless of
1753 * cached scanner positions.
1754 */
1755 if (is_via_compact_memory(cc->order))
1756 __reset_isolation_suitable(zone);
1757
1758 if (is_via_compact_memory(cc->order) || 1756 if (is_via_compact_memory(cc->order) ||
1759 !compaction_deferred(zone, cc->order)) 1757 !compaction_deferred(zone, cc->order))
1760 compact_zone(zone, cc); 1758 compact_zone(zone, cc);
@@ -1790,6 +1788,7 @@ static void compact_node(int nid)
1790 .order = -1, 1788 .order = -1,
1791 .mode = MIGRATE_SYNC, 1789 .mode = MIGRATE_SYNC,
1792 .ignore_skip_hint = true, 1790 .ignore_skip_hint = true,
1791 .whole_zone = true,
1793 }; 1792 };
1794 1793
1795 __compact_pgdat(NODE_DATA(nid), &cc); 1794 __compact_pgdat(NODE_DATA(nid), &cc);
diff --git a/mm/internal.h b/mm/internal.h
index 1501304f87a4..5214bf8e3171 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -179,7 +179,7 @@ struct compact_control {
179 enum migrate_mode mode; /* Async or sync migration mode */ 179 enum migrate_mode mode; /* Async or sync migration mode */
180 bool ignore_skip_hint; /* Scan blocks even if marked skip */ 180 bool ignore_skip_hint; /* Scan blocks even if marked skip */
181 bool direct_compaction; /* False from kcompactd or /proc/... */ 181 bool direct_compaction; /* False from kcompactd or /proc/... */
182 bool whole_zone; /* Whole zone has been scanned */ 182 bool whole_zone; /* Whole zone should/has been scanned */
183 int order; /* order a direct compactor needs */ 183 int order; /* order a direct compactor needs */
184 const gfp_t gfp_mask; /* gfp mask of a direct compactor */ 184 const gfp_t gfp_mask; /* gfp mask of a direct compactor */
185 const unsigned int alloc_flags; /* alloc flags of a direct compactor */ 185 const unsigned int alloc_flags; /* alloc flags of a direct compactor */