summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorMel Gorman <mgorman@techsingularity.net>2016-05-19 20:13:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 22:12:14 -0400
commit682a3385e7734fa3abbd504cbeb5fe91793f1827 (patch)
tree1371b57acda5bb81e15bed95d82d155dae00bf65 /mm/page_alloc.c
parent060e74173f292fb3e0398b3dca8765568d195ff1 (diff)
mm, page_alloc: inline the fast path of the zonelist iterator
The page allocator iterates through a zonelist for zones that match the addressing limitations and nodemask of the caller but many allocations will not be restricted. Despite this, there is always functional call overhead which builds up. This patch inlines the optimistic basic case and only calls the iterator function for the complex case. A hindrance was the fact that cpuset_current_mems_allowed is used in the fastpath as the allowed nodemask even though all nodes are allowed on most systems. The patch handles this by only considering cpuset_current_mems_allowed if a cpuset exists. As well as being faster in the fast-path, this removes some junk in the slowpath. The performance difference on a page allocator microbenchmark is; 4.6.0-rc2 4.6.0-rc2 statinline-v1r20 optiter-v1r20 Min alloc-odr0-1 412.00 ( 0.00%) 382.00 ( 7.28%) Min alloc-odr0-2 301.00 ( 0.00%) 282.00 ( 6.31%) Min alloc-odr0-4 247.00 ( 0.00%) 233.00 ( 5.67%) Min alloc-odr0-8 215.00 ( 0.00%) 203.00 ( 5.58%) Min alloc-odr0-16 199.00 ( 0.00%) 188.00 ( 5.53%) Min alloc-odr0-32 191.00 ( 0.00%) 182.00 ( 4.71%) Min alloc-odr0-64 187.00 ( 0.00%) 177.00 ( 5.35%) Min alloc-odr0-128 185.00 ( 0.00%) 175.00 ( 5.41%) Min alloc-odr0-256 193.00 ( 0.00%) 184.00 ( 4.66%) Min alloc-odr0-512 207.00 ( 0.00%) 197.00 ( 4.83%) Min alloc-odr0-1024 213.00 ( 0.00%) 203.00 ( 4.69%) Min alloc-odr0-2048 220.00 ( 0.00%) 209.00 ( 5.00%) Min alloc-odr0-4096 226.00 ( 0.00%) 214.00 ( 5.31%) Min alloc-odr0-8192 229.00 ( 0.00%) 218.00 ( 4.80%) Min alloc-odr0-16384 229.00 ( 0.00%) 219.00 ( 4.37%) perf indicated that next_zones_zonelist disappeared in the profile and __next_zones_zonelist did not appear. This is expected as the micro-benchmark would hit the inlined fast-path every time. Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c26
1 files changed, 9 insertions, 17 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 36384baa74e1..789e5f065e8d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3192,17 +3192,6 @@ retry:
3192 */ 3192 */
3193 alloc_flags = gfp_to_alloc_flags(gfp_mask); 3193 alloc_flags = gfp_to_alloc_flags(gfp_mask);
3194 3194
3195 /*
3196 * Find the true preferred zone if the allocation is unconstrained by
3197 * cpusets.
3198 */
3199 if (!(alloc_flags & ALLOC_CPUSET) && !ac->nodemask) {
3200 struct zoneref *preferred_zoneref;
3201 preferred_zoneref = first_zones_zonelist(ac->zonelist,
3202 ac->high_zoneidx, NULL, &ac->preferred_zone);
3203 ac->classzone_idx = zonelist_zone_idx(preferred_zoneref);
3204 }
3205
3206 /* This is the last chance, in general, before the goto nopage. */ 3195 /* This is the last chance, in general, before the goto nopage. */
3207 page = get_page_from_freelist(gfp_mask, order, 3196 page = get_page_from_freelist(gfp_mask, order,
3208 alloc_flags & ~ALLOC_NO_WATERMARKS, ac); 3197 alloc_flags & ~ALLOC_NO_WATERMARKS, ac);
@@ -3358,14 +3347,21 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
3358 struct zoneref *preferred_zoneref; 3347 struct zoneref *preferred_zoneref;
3359 struct page *page = NULL; 3348 struct page *page = NULL;
3360 unsigned int cpuset_mems_cookie; 3349 unsigned int cpuset_mems_cookie;
3361 int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR; 3350 int alloc_flags = ALLOC_WMARK_LOW|ALLOC_FAIR;
3362 gfp_t alloc_mask; /* The gfp_t that was actually used for allocation */ 3351 gfp_t alloc_mask; /* The gfp_t that was actually used for allocation */
3363 struct alloc_context ac = { 3352 struct alloc_context ac = {
3364 .high_zoneidx = gfp_zone(gfp_mask), 3353 .high_zoneidx = gfp_zone(gfp_mask),
3354 .zonelist = zonelist,
3365 .nodemask = nodemask, 3355 .nodemask = nodemask,
3366 .migratetype = gfpflags_to_migratetype(gfp_mask), 3356 .migratetype = gfpflags_to_migratetype(gfp_mask),
3367 }; 3357 };
3368 3358
3359 if (cpusets_enabled()) {
3360 alloc_flags |= ALLOC_CPUSET;
3361 if (!ac.nodemask)
3362 ac.nodemask = &cpuset_current_mems_allowed;
3363 }
3364
3369 gfp_mask &= gfp_allowed_mask; 3365 gfp_mask &= gfp_allowed_mask;
3370 3366
3371 lockdep_trace_alloc(gfp_mask); 3367 lockdep_trace_alloc(gfp_mask);
@@ -3389,16 +3385,12 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
3389retry_cpuset: 3385retry_cpuset:
3390 cpuset_mems_cookie = read_mems_allowed_begin(); 3386 cpuset_mems_cookie = read_mems_allowed_begin();
3391 3387
3392 /* We set it here, as __alloc_pages_slowpath might have changed it */
3393 ac.zonelist = zonelist;
3394
3395 /* Dirty zone balancing only done in the fast path */ 3388 /* Dirty zone balancing only done in the fast path */
3396 ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE); 3389 ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE);
3397 3390
3398 /* The preferred zone is used for statistics later */ 3391 /* The preferred zone is used for statistics later */
3399 preferred_zoneref = first_zones_zonelist(ac.zonelist, ac.high_zoneidx, 3392 preferred_zoneref = first_zones_zonelist(ac.zonelist, ac.high_zoneidx,
3400 ac.nodemask ? : &cpuset_current_mems_allowed, 3393 ac.nodemask, &ac.preferred_zone);
3401 &ac.preferred_zone);
3402 if (!ac.preferred_zone) 3394 if (!ac.preferred_zone)
3403 goto out; 3395 goto out;
3404 ac.classzone_idx = zonelist_zone_idx(preferred_zoneref); 3396 ac.classzone_idx = zonelist_zone_idx(preferred_zoneref);