diff options
author | Mel Gorman <mgorman@suse.de> | 2014-08-06 19:07:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 21:01:20 -0400 |
commit | 3484b2de9499df23c4604a513b36f96326ae81ad (patch) | |
tree | fbaaed00603474887953459b01e09c5b9ff7379f /mm | |
parent | 24b7e5819ad5cbef2b7c7376510862aa8319d240 (diff) |
mm: rearrange zone fields into read-only, page alloc, statistics and page reclaim lines
The arrangement of struct zone has changed over time and now it has
reached the point where there is some inappropriate sharing going on.
On x86-64 for example
o The zone->node field is shared with the zone lock and zone->node is
accessed frequently from the page allocator due to the fair zone
allocation policy.
o span_seqlock is almost never used by shares a line with free_area
o Some zone statistics share a cache line with the LRU lock so
reclaim-intensive and allocator-intensive workloads can bounce the cache
line on a stat update
This patch rearranges struct zone to put read-only and read-mostly
fields together and then splits the page allocator intensive fields, the
zone statistics and the page reclaim intensive fields into their own
cache lines. Note that the type of lowmem_reserve changes due to the
watermark calculations being signed and avoiding a signed/unsigned
conversion there.
On the test configuration I used the overall size of struct zone shrunk
by one cache line. On smaller machines, this is not likely to be
noticable. However, on a 4-node NUMA machine running tiobench the
system CPU overhead is reduced by this patch.
3.16.0-rc3 3.16.0-rc3
vanillarearrange-v5r9
User 746.94 759.78
System 65336.22 58350.98
Elapsed 27553.52 27282.02
Signed-off-by: Mel Gorman <mgorman@suse.de>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 7 | ||||
-rw-r--r-- | mm/vmstat.c | 4 |
2 files changed, 5 insertions, 6 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0987ac9f0a4e..b7381d11f021 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1708,7 +1708,6 @@ static bool __zone_watermark_ok(struct zone *z, unsigned int order, | |||
1708 | { | 1708 | { |
1709 | /* free_pages my go negative - that's OK */ | 1709 | /* free_pages my go negative - that's OK */ |
1710 | long min = mark; | 1710 | long min = mark; |
1711 | long lowmem_reserve = z->lowmem_reserve[classzone_idx]; | ||
1712 | int o; | 1711 | int o; |
1713 | long free_cma = 0; | 1712 | long free_cma = 0; |
1714 | 1713 | ||
@@ -1723,7 +1722,7 @@ static bool __zone_watermark_ok(struct zone *z, unsigned int order, | |||
1723 | free_cma = zone_page_state(z, NR_FREE_CMA_PAGES); | 1722 | free_cma = zone_page_state(z, NR_FREE_CMA_PAGES); |
1724 | #endif | 1723 | #endif |
1725 | 1724 | ||
1726 | if (free_pages - free_cma <= min + lowmem_reserve) | 1725 | if (free_pages - free_cma <= min + z->lowmem_reserve[classzone_idx]) |
1727 | return false; | 1726 | return false; |
1728 | for (o = 0; o < order; o++) { | 1727 | for (o = 0; o < order; o++) { |
1729 | /* At the next order, this order's pages become unavailable */ | 1728 | /* At the next order, this order's pages become unavailable */ |
@@ -3254,7 +3253,7 @@ void show_free_areas(unsigned int filter) | |||
3254 | ); | 3253 | ); |
3255 | printk("lowmem_reserve[]:"); | 3254 | printk("lowmem_reserve[]:"); |
3256 | for (i = 0; i < MAX_NR_ZONES; i++) | 3255 | for (i = 0; i < MAX_NR_ZONES; i++) |
3257 | printk(" %lu", zone->lowmem_reserve[i]); | 3256 | printk(" %ld", zone->lowmem_reserve[i]); |
3258 | printk("\n"); | 3257 | printk("\n"); |
3259 | } | 3258 | } |
3260 | 3259 | ||
@@ -5575,7 +5574,7 @@ static void calculate_totalreserve_pages(void) | |||
5575 | for_each_online_pgdat(pgdat) { | 5574 | for_each_online_pgdat(pgdat) { |
5576 | for (i = 0; i < MAX_NR_ZONES; i++) { | 5575 | for (i = 0; i < MAX_NR_ZONES; i++) { |
5577 | struct zone *zone = pgdat->node_zones + i; | 5576 | struct zone *zone = pgdat->node_zones + i; |
5578 | unsigned long max = 0; | 5577 | long max = 0; |
5579 | 5578 | ||
5580 | /* Find valid and maximum lowmem_reserve in the zone */ | 5579 | /* Find valid and maximum lowmem_reserve in the zone */ |
5581 | for (j = i; j < MAX_NR_ZONES; j++) { | 5580 | for (j = i; j < MAX_NR_ZONES; j++) { |
diff --git a/mm/vmstat.c b/mm/vmstat.c index b37bd49bfd55..8267f77d1875 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c | |||
@@ -1077,10 +1077,10 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1077 | zone_page_state(zone, i)); | 1077 | zone_page_state(zone, i)); |
1078 | 1078 | ||
1079 | seq_printf(m, | 1079 | seq_printf(m, |
1080 | "\n protection: (%lu", | 1080 | "\n protection: (%ld", |
1081 | zone->lowmem_reserve[0]); | 1081 | zone->lowmem_reserve[0]); |
1082 | for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) | 1082 | for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) |
1083 | seq_printf(m, ", %lu", zone->lowmem_reserve[i]); | 1083 | seq_printf(m, ", %ld", zone->lowmem_reserve[i]); |
1084 | seq_printf(m, | 1084 | seq_printf(m, |
1085 | ")" | 1085 | ")" |
1086 | "\n pagesets"); | 1086 | "\n pagesets"); |