Skip to content

Commit c33d6c0

Browse files
gormanmtorvalds
authored andcommitted
mm, page_alloc: avoid looking up the first zone in a zonelist twice
The allocator fast path looks up the first usable zone in a zonelist and then get_page_from_freelist does the same job in the zonelist iterator. This patch preserves the necessary information. 4.6.0-rc2 4.6.0-rc2 fastmark-v1r20 initonce-v1r20 Min alloc-odr0-1 364.00 ( 0.00%) 359.00 ( 1.37%) Min alloc-odr0-2 262.00 ( 0.00%) 260.00 ( 0.76%) Min alloc-odr0-4 214.00 ( 0.00%) 214.00 ( 0.00%) Min alloc-odr0-8 186.00 ( 0.00%) 186.00 ( 0.00%) Min alloc-odr0-16 173.00 ( 0.00%) 173.00 ( 0.00%) Min alloc-odr0-32 165.00 ( 0.00%) 165.00 ( 0.00%) Min alloc-odr0-64 161.00 ( 0.00%) 162.00 ( -0.62%) Min alloc-odr0-128 159.00 ( 0.00%) 161.00 ( -1.26%) Min alloc-odr0-256 168.00 ( 0.00%) 170.00 ( -1.19%) Min alloc-odr0-512 180.00 ( 0.00%) 181.00 ( -0.56%) Min alloc-odr0-1024 190.00 ( 0.00%) 190.00 ( 0.00%) Min alloc-odr0-2048 196.00 ( 0.00%) 196.00 ( 0.00%) Min alloc-odr0-4096 202.00 ( 0.00%) 202.00 ( 0.00%) Min alloc-odr0-8192 206.00 ( 0.00%) 205.00 ( 0.49%) Min alloc-odr0-16384 206.00 ( 0.00%) 205.00 ( 0.49%) The benefit is negligible and the results are within the noise but each cycle counts. Signed-off-by: Mel Gorman <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Jesper Dangaard Brouer <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 48ee5f3 commit c33d6c0

File tree

5 files changed

+43
-40
lines changed

5 files changed

+43
-40
lines changed

fs/buffer.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,17 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
255255
*/
256256
static void free_more_memory(void)
257257
{
258-
struct zone *zone;
258+
struct zoneref *z;
259259
int nid;
260260

261261
wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM);
262262
yield();
263263

264264
for_each_online_node(nid) {
265-
(void)first_zones_zonelist(node_zonelist(nid, GFP_NOFS),
266-
gfp_zone(GFP_NOFS), NULL,
267-
&zone);
268-
if (zone)
265+
266+
z = first_zones_zonelist(node_zonelist(nid, GFP_NOFS),
267+
gfp_zone(GFP_NOFS), NULL);
268+
if (z->zone)
269269
try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0,
270270
GFP_NOFS, NULL);
271271
}

include/linux/mmzone.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -959,13 +959,10 @@ static __always_inline struct zoneref *next_zones_zonelist(struct zoneref *z,
959959
*/
960960
static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
961961
enum zone_type highest_zoneidx,
962-
nodemask_t *nodes,
963-
struct zone **zone)
962+
nodemask_t *nodes)
964963
{
965-
struct zoneref *z = next_zones_zonelist(zonelist->_zonerefs,
964+
return next_zones_zonelist(zonelist->_zonerefs,
966965
highest_zoneidx, nodes);
967-
*zone = zonelist_zone(z);
968-
return z;
969966
}
970967

971968
/**
@@ -980,10 +977,17 @@ static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
980977
* within a given nodemask
981978
*/
982979
#define for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \
983-
for (z = first_zones_zonelist(zlist, highidx, nodemask, &zone); \
980+
for (z = first_zones_zonelist(zlist, highidx, nodemask), zone = zonelist_zone(z); \
984981
zone; \
985982
z = next_zones_zonelist(++z, highidx, nodemask), \
986-
zone = zonelist_zone(z)) \
983+
zone = zonelist_zone(z))
984+
985+
#define for_next_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \
986+
for (zone = z->zone; \
987+
zone; \
988+
z = next_zones_zonelist(++z, highidx, nodemask), \
989+
zone = zonelist_zone(z))
990+
987991

988992
/**
989993
* for_each_zone_zonelist - helper macro to iterate over valid zones in a zonelist at or below a given zone index

mm/internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ extern pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address);
102102
struct alloc_context {
103103
struct zonelist *zonelist;
104104
nodemask_t *nodemask;
105-
struct zone *preferred_zone;
105+
struct zoneref *preferred_zoneref;
106106
int classzone_idx;
107107
int migratetype;
108108
enum zone_type high_zoneidx;

mm/mempolicy.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,18 +1739,18 @@ unsigned int mempolicy_slab_node(void)
17391739
return interleave_nodes(policy);
17401740

17411741
case MPOL_BIND: {
1742+
struct zoneref *z;
1743+
17421744
/*
17431745
* Follow bind policy behavior and start allocation at the
17441746
* first node.
17451747
*/
17461748
struct zonelist *zonelist;
1747-
struct zone *zone;
17481749
enum zone_type highest_zoneidx = gfp_zone(GFP_KERNEL);
17491750
zonelist = &NODE_DATA(node)->node_zonelists[0];
1750-
(void)first_zones_zonelist(zonelist, highest_zoneidx,
1751-
&policy->v.nodes,
1752-
&zone);
1753-
return zone ? zone->node : node;
1751+
z = first_zones_zonelist(zonelist, highest_zoneidx,
1752+
&policy->v.nodes);
1753+
return z->zone ? z->zone->node : node;
17541754
}
17551755

17561756
default:
@@ -2266,7 +2266,7 @@ static void sp_free(struct sp_node *n)
22662266
int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long addr)
22672267
{
22682268
struct mempolicy *pol;
2269-
struct zone *zone;
2269+
struct zoneref *z;
22702270
int curnid = page_to_nid(page);
22712271
unsigned long pgoff;
22722272
int thiscpu = raw_smp_processor_id();
@@ -2298,6 +2298,7 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
22982298
break;
22992299

23002300
case MPOL_BIND:
2301+
23012302
/*
23022303
* allows binding to multiple nodes.
23032304
* use current page if in policy nodemask,
@@ -2306,11 +2307,11 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
23062307
*/
23072308
if (node_isset(curnid, pol->v.nodes))
23082309
goto out;
2309-
(void)first_zones_zonelist(
2310+
z = first_zones_zonelist(
23102311
node_zonelist(numa_node_id(), GFP_HIGHUSER),
23112312
gfp_zone(GFP_HIGHUSER),
2312-
&pol->v.nodes, &zone);
2313-
polnid = zone->node;
2313+
&pol->v.nodes);
2314+
polnid = z->zone->node;
23142315
break;
23152316

23162317
default:

mm/page_alloc.c

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,7 +2704,7 @@ static struct page *
27042704
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
27052705
const struct alloc_context *ac)
27062706
{
2707-
struct zoneref *z;
2707+
struct zoneref *z = ac->preferred_zoneref;
27082708
struct zone *zone;
27092709
bool fair_skipped = false;
27102710
bool apply_fair = (alloc_flags & ALLOC_FAIR);
@@ -2714,7 +2714,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
27142714
* Scan zonelist, looking for a zone with enough free.
27152715
* See also __cpuset_node_allowed() comment in kernel/cpuset.c.
27162716
*/
2717-
for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
2717+
for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
27182718
ac->nodemask) {
27192719
struct page *page;
27202720
unsigned long mark;
@@ -2734,7 +2734,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
27342734
fair_skipped = true;
27352735
continue;
27362736
}
2737-
if (!zone_local(ac->preferred_zone, zone)) {
2737+
if (!zone_local(ac->preferred_zoneref->zone, zone)) {
27382738
if (fair_skipped)
27392739
goto reset_fair;
27402740
apply_fair = false;
@@ -2780,7 +2780,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
27802780
goto try_this_zone;
27812781

27822782
if (zone_reclaim_mode == 0 ||
2783-
!zone_allows_reclaim(ac->preferred_zone, zone))
2783+
!zone_allows_reclaim(ac->preferred_zoneref->zone, zone))
27842784
continue;
27852785

27862786
ret = zone_reclaim(zone, gfp_mask, order);
@@ -2802,7 +2802,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
28022802
}
28032803

28042804
try_this_zone:
2805-
page = buffered_rmqueue(ac->preferred_zone, zone, order,
2805+
page = buffered_rmqueue(ac->preferred_zoneref->zone, zone, order,
28062806
gfp_mask, alloc_flags, ac->migratetype);
28072807
if (page) {
28082808
if (prep_new_page(page, order, gfp_mask, alloc_flags))
@@ -2831,7 +2831,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
28312831
reset_fair:
28322832
apply_fair = false;
28332833
fair_skipped = false;
2834-
reset_alloc_batches(ac->preferred_zone);
2834+
reset_alloc_batches(ac->preferred_zoneref->zone);
28352835
goto zonelist_scan;
28362836
}
28372837

@@ -3114,7 +3114,7 @@ static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac)
31143114

31153115
for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
31163116
ac->high_zoneidx, ac->nodemask)
3117-
wakeup_kswapd(zone, order, zone_idx(ac->preferred_zone));
3117+
wakeup_kswapd(zone, order, zonelist_zone_idx(ac->preferred_zoneref));
31183118
}
31193119

31203120
static inline unsigned int
@@ -3332,7 +3332,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
33323332
if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
33333333
((gfp_mask & __GFP_REPEAT) && pages_reclaimed < (1 << order))) {
33343334
/* Wait for some write requests to complete then retry */
3335-
wait_iff_congested(ac->preferred_zone, BLK_RW_ASYNC, HZ/50);
3335+
wait_iff_congested(ac->preferred_zoneref->zone, BLK_RW_ASYNC, HZ/50);
33363336
goto retry;
33373337
}
33383338

@@ -3370,7 +3370,6 @@ struct page *
33703370
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
33713371
struct zonelist *zonelist, nodemask_t *nodemask)
33723372
{
3373-
struct zoneref *preferred_zoneref;
33743373
struct page *page;
33753374
unsigned int cpuset_mems_cookie;
33763375
unsigned int alloc_flags = ALLOC_WMARK_LOW|ALLOC_FAIR;
@@ -3416,14 +3415,14 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
34163415
ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE);
34173416

34183417
/* The preferred zone is used for statistics later */
3419-
preferred_zoneref = first_zones_zonelist(ac.zonelist, ac.high_zoneidx,
3420-
ac.nodemask, &ac.preferred_zone);
3421-
if (!ac.preferred_zone) {
3418+
ac.preferred_zoneref = first_zones_zonelist(ac.zonelist,
3419+
ac.high_zoneidx, ac.nodemask);
3420+
if (!ac.preferred_zoneref) {
34223421
page = NULL;
34233422
goto no_zone;
34243423
}
34253424

3426-
ac.classzone_idx = zonelist_zone_idx(preferred_zoneref);
3425+
ac.classzone_idx = zonelist_zone_idx(ac.preferred_zoneref);
34273426

34283427
/* First allocation attempt */
34293428
page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);
@@ -4462,13 +4461,12 @@ static void build_zonelists(pg_data_t *pgdat)
44624461
*/
44634462
int local_memory_node(int node)
44644463
{
4465-
struct zone *zone;
4464+
struct zoneref *z;
44664465

4467-
(void)first_zones_zonelist(node_zonelist(node, GFP_KERNEL),
4466+
z = first_zones_zonelist(node_zonelist(node, GFP_KERNEL),
44684467
gfp_zone(GFP_KERNEL),
4469-
NULL,
4470-
&zone);
4471-
return zone->node;
4468+
NULL);
4469+
return z->zone->node;
44724470
}
44734471
#endif
44744472

0 commit comments

Comments
 (0)