summaryrefslogtreecommitdiffstats
path: root/mm/compaction.c
diff options
context:
space:
mode:
authorMel Gorman <mgorman@techsingularity.net>2019-03-05 18:45:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 00:07:17 -0500
commit5e1f0f098b4649fad53011246bcaeff011ffdf5d (patch)
tree88e1399008fd89a44a52b3dabb6da42eef15da05 /mm/compaction.c
parente332f741a8dd1ec9a6dc8aa997296ecbfe64323e (diff)
mm, compaction: capture a page under direct compaction
Compaction is inherently race-prone as a suitable page freed during compaction can be allocated by any parallel task. This patch uses a capture_control structure to isolate a page immediately when it is freed by a direct compactor in the slow path of the page allocator. The intent is to avoid redundant scanning. 5.0.0-rc1 5.0.0-rc1 selective-v3r17 capture-v3r19 Amean fault-both-1 0.00 ( 0.00%) 0.00 * 0.00%* Amean fault-both-3 2582.11 ( 0.00%) 2563.68 ( 0.71%) Amean fault-both-5 4500.26 ( 0.00%) 4233.52 ( 5.93%) Amean fault-both-7 5819.53 ( 0.00%) 6333.65 ( -8.83%) Amean fault-both-12 9321.18 ( 0.00%) 9759.38 ( -4.70%) Amean fault-both-18 9782.76 ( 0.00%) 10338.76 ( -5.68%) Amean fault-both-24 15272.81 ( 0.00%) 13379.55 * 12.40%* Amean fault-both-30 15121.34 ( 0.00%) 16158.25 ( -6.86%) Amean fault-both-32 18466.67 ( 0.00%) 18971.21 ( -2.73%) Latency is only moderately affected but the devil is in the details. A closer examination indicates that base page fault latency is reduced but latency of huge pages is increased as it takes creater care to succeed. Part of the "problem" is that allocation success rates are close to 100% even when under pressure and compaction gets harder 5.0.0-rc1 5.0.0-rc1 selective-v3r17 capture-v3r19 Percentage huge-3 96.70 ( 0.00%) 98.23 ( 1.58%) Percentage huge-5 96.99 ( 0.00%) 95.30 ( -1.75%) Percentage huge-7 94.19 ( 0.00%) 97.24 ( 3.24%) Percentage huge-12 94.95 ( 0.00%) 97.35 ( 2.53%) Percentage huge-18 96.74 ( 0.00%) 97.30 ( 0.58%) Percentage huge-24 97.07 ( 0.00%) 97.55 ( 0.50%) Percentage huge-30 95.69 ( 0.00%) 98.50 ( 2.95%) Percentage huge-32 96.70 ( 0.00%) 99.27 ( 2.65%) And scan rates are reduced as expected by 6% for the migration scanner and 29% for the free scanner indicating that there is less redundant work. Compaction migrate scanned 20815362 19573286 Compaction free scanned 16352612 11510663 [mgorman@techsingularity.net: remove redundant check] Link: http://lkml.kernel.org/r/20190201143853.GH9565@techsingularity.net Link: http://lkml.kernel.org/r/20190118175136.31341-23-mgorman@techsingularity.net Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: David Rientjes <rientjes@google.com> Cc: YueHaibing <yuehaibing@huawei.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/compaction.c')
-rw-r--r--mm/compaction.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/mm/compaction.c b/mm/compaction.c
index 3084cee77fda..1cc871da3fda 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -2056,7 +2056,8 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
2056 return false; 2056 return false;
2057} 2057}
2058 2058
2059static enum compact_result compact_zone(struct compact_control *cc) 2059static enum compact_result
2060compact_zone(struct compact_control *cc, struct capture_control *capc)
2060{ 2061{
2061 enum compact_result ret; 2062 enum compact_result ret;
2062 unsigned long start_pfn = cc->zone->zone_start_pfn; 2063 unsigned long start_pfn = cc->zone->zone_start_pfn;
@@ -2225,6 +2226,11 @@ check_drain:
2225 } 2226 }
2226 } 2227 }
2227 2228
2229 /* Stop if a page has been captured */
2230 if (capc && capc->page) {
2231 ret = COMPACT_SUCCESS;
2232 break;
2233 }
2228 } 2234 }
2229 2235
2230out: 2236out:
@@ -2258,7 +2264,8 @@ out:
2258 2264
2259static enum compact_result compact_zone_order(struct zone *zone, int order, 2265static enum compact_result compact_zone_order(struct zone *zone, int order,
2260 gfp_t gfp_mask, enum compact_priority prio, 2266 gfp_t gfp_mask, enum compact_priority prio,
2261 unsigned int alloc_flags, int classzone_idx) 2267 unsigned int alloc_flags, int classzone_idx,
2268 struct page **capture)
2262{ 2269{
2263 enum compact_result ret; 2270 enum compact_result ret;
2264 struct compact_control cc = { 2271 struct compact_control cc = {
@@ -2279,14 +2286,24 @@ static enum compact_result compact_zone_order(struct zone *zone, int order,
2279 .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY), 2286 .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY),
2280 .ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY) 2287 .ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY)
2281 }; 2288 };
2289 struct capture_control capc = {
2290 .cc = &cc,
2291 .page = NULL,
2292 };
2293
2294 if (capture)
2295 current->capture_control = &capc;
2282 INIT_LIST_HEAD(&cc.freepages); 2296 INIT_LIST_HEAD(&cc.freepages);
2283 INIT_LIST_HEAD(&cc.migratepages); 2297 INIT_LIST_HEAD(&cc.migratepages);
2284 2298
2285 ret = compact_zone(&cc); 2299 ret = compact_zone(&cc, &capc);
2286 2300
2287 VM_BUG_ON(!list_empty(&cc.freepages)); 2301 VM_BUG_ON(!list_empty(&cc.freepages));
2288 VM_BUG_ON(!list_empty(&cc.migratepages)); 2302 VM_BUG_ON(!list_empty(&cc.migratepages));
2289 2303
2304 *capture = capc.page;
2305 current->capture_control = NULL;
2306
2290 return ret; 2307 return ret;
2291} 2308}
2292 2309
@@ -2304,7 +2321,7 @@ int sysctl_extfrag_threshold = 500;
2304 */ 2321 */
2305enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order, 2322enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
2306 unsigned int alloc_flags, const struct alloc_context *ac, 2323 unsigned int alloc_flags, const struct alloc_context *ac,
2307 enum compact_priority prio) 2324 enum compact_priority prio, struct page **capture)
2308{ 2325{
2309 int may_perform_io = gfp_mask & __GFP_IO; 2326 int may_perform_io = gfp_mask & __GFP_IO;
2310 struct zoneref *z; 2327 struct zoneref *z;
@@ -2332,7 +2349,7 @@ enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
2332 } 2349 }
2333 2350
2334 status = compact_zone_order(zone, order, gfp_mask, prio, 2351 status = compact_zone_order(zone, order, gfp_mask, prio,
2335 alloc_flags, ac_classzone_idx(ac)); 2352 alloc_flags, ac_classzone_idx(ac), capture);
2336 rc = max(status, rc); 2353 rc = max(status, rc);
2337 2354
2338 /* The allocation should succeed, stop compacting */ 2355 /* The allocation should succeed, stop compacting */
@@ -2400,7 +2417,7 @@ static void compact_node(int nid)
2400 INIT_LIST_HEAD(&cc.freepages); 2417 INIT_LIST_HEAD(&cc.freepages);
2401 INIT_LIST_HEAD(&cc.migratepages); 2418 INIT_LIST_HEAD(&cc.migratepages);
2402 2419
2403 compact_zone(&cc); 2420 compact_zone(&cc, NULL);
2404 2421
2405 VM_BUG_ON(!list_empty(&cc.freepages)); 2422 VM_BUG_ON(!list_empty(&cc.freepages));
2406 VM_BUG_ON(!list_empty(&cc.migratepages)); 2423 VM_BUG_ON(!list_empty(&cc.migratepages));
@@ -2535,7 +2552,7 @@ static void kcompactd_do_work(pg_data_t *pgdat)
2535 2552
2536 if (kthread_should_stop()) 2553 if (kthread_should_stop())
2537 return; 2554 return;
2538 status = compact_zone(&cc); 2555 status = compact_zone(&cc, NULL);
2539 2556
2540 if (status == COMPACT_SUCCESS) { 2557 if (status == COMPACT_SUCCESS) {
2541 compaction_defer_reset(zone, cc.order, false); 2558 compaction_defer_reset(zone, cc.order, false);