summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorMel Gorman <mgorman@techsingularity.net>2016-05-19 20:14:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 22:12:14 -0400
commit479f854a207ce2b97545a0a83856778b541063d0 (patch)
treeaf031f22aa45f1c7140bbe670b69b72994facc4f /mm/page_alloc.c
parent4db7548ccbd9ec8e666f35df4a530f55904dec39 (diff)
mm, page_alloc: defer debugging checks of pages allocated from the PCP
Every page allocated checks a number of page fields for validity. This catches corruption bugs of pages that are already freed but it is expensive. This patch weakens the debugging check by checking PCP pages only when the PCP lists are being refilled. All compound pages are checked. This potentially avoids debugging checks entirely if the PCP lists are never emptied and refilled so some corruption issues may be missed. Full checking requires DEBUG_VM. With the two deferred debugging patches applied, the impact to a page allocator microbenchmark is 4.6.0-rc3 4.6.0-rc3 inline-v3r6 deferalloc-v3r7 Min alloc-odr0-1 344.00 ( 0.00%) 317.00 ( 7.85%) Min alloc-odr0-2 248.00 ( 0.00%) 231.00 ( 6.85%) Min alloc-odr0-4 209.00 ( 0.00%) 192.00 ( 8.13%) Min alloc-odr0-8 181.00 ( 0.00%) 166.00 ( 8.29%) Min alloc-odr0-16 168.00 ( 0.00%) 154.00 ( 8.33%) Min alloc-odr0-32 161.00 ( 0.00%) 148.00 ( 8.07%) Min alloc-odr0-64 158.00 ( 0.00%) 145.00 ( 8.23%) Min alloc-odr0-128 156.00 ( 0.00%) 143.00 ( 8.33%) Min alloc-odr0-256 168.00 ( 0.00%) 154.00 ( 8.33%) Min alloc-odr0-512 178.00 ( 0.00%) 167.00 ( 6.18%) Min alloc-odr0-1024 186.00 ( 0.00%) 174.00 ( 6.45%) Min alloc-odr0-2048 192.00 ( 0.00%) 180.00 ( 6.25%) Min alloc-odr0-4096 198.00 ( 0.00%) 184.00 ( 7.07%) Min alloc-odr0-8192 200.00 ( 0.00%) 188.00 ( 6.00%) Min alloc-odr0-16384 201.00 ( 0.00%) 188.00 ( 6.47%) Min free-odr0-1 189.00 ( 0.00%) 180.00 ( 4.76%) Min free-odr0-2 132.00 ( 0.00%) 126.00 ( 4.55%) Min free-odr0-4 104.00 ( 0.00%) 99.00 ( 4.81%) Min free-odr0-8 90.00 ( 0.00%) 85.00 ( 5.56%) Min free-odr0-16 84.00 ( 0.00%) 80.00 ( 4.76%) Min free-odr0-32 80.00 ( 0.00%) 76.00 ( 5.00%) Min free-odr0-64 78.00 ( 0.00%) 74.00 ( 5.13%) Min free-odr0-128 77.00 ( 0.00%) 73.00 ( 5.19%) Min free-odr0-256 94.00 ( 0.00%) 91.00 ( 3.19%) Min free-odr0-512 108.00 ( 0.00%) 112.00 ( -3.70%) Min free-odr0-1024 115.00 ( 0.00%) 118.00 ( -2.61%) Min free-odr0-2048 120.00 ( 0.00%) 125.00 ( -4.17%) Min free-odr0-4096 123.00 ( 0.00%) 129.00 ( -4.88%) Min free-odr0-8192 126.00 ( 0.00%) 130.00 ( -3.17%) Min free-odr0-16384 126.00 ( 0.00%) 131.00 ( -3.97%) Note that the free paths for large numbers of pages is impacted as the debugging cost gets shifted into that path when the page data is no longer necessarily cache-hot. Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Acked-by: 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.c92
1 files changed, 64 insertions, 28 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 759d3f60bea0..193ed34a2780 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1714,7 +1714,41 @@ static inline bool free_pages_prezeroed(bool poisoned)
1714 page_poisoning_enabled() && poisoned; 1714 page_poisoning_enabled() && poisoned;
1715} 1715}
1716 1716
1717static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, 1717#ifdef CONFIG_DEBUG_VM
1718static bool check_pcp_refill(struct page *page)
1719{
1720 return false;
1721}
1722
1723static bool check_new_pcp(struct page *page)
1724{
1725 return check_new_page(page);
1726}
1727#else
1728static bool check_pcp_refill(struct page *page)
1729{
1730 return check_new_page(page);
1731}
1732static bool check_new_pcp(struct page *page)
1733{
1734 return false;
1735}
1736#endif /* CONFIG_DEBUG_VM */
1737
1738static bool check_new_pages(struct page *page, unsigned int order)
1739{
1740 int i;
1741 for (i = 0; i < (1 << order); i++) {
1742 struct page *p = page + i;
1743
1744 if (unlikely(check_new_page(p)))
1745 return true;
1746 }
1747
1748 return false;
1749}
1750
1751static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
1718 unsigned int alloc_flags) 1752 unsigned int alloc_flags)
1719{ 1753{
1720 int i; 1754 int i;
@@ -1722,8 +1756,6 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
1722 1756
1723 for (i = 0; i < (1 << order); i++) { 1757 for (i = 0; i < (1 << order); i++) {
1724 struct page *p = page + i; 1758 struct page *p = page + i;
1725 if (unlikely(check_new_page(p)))
1726 return 1;
1727 if (poisoned) 1759 if (poisoned)
1728 poisoned &= page_is_poisoned(p); 1760 poisoned &= page_is_poisoned(p);
1729 } 1761 }
@@ -1755,8 +1787,6 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
1755 set_page_pfmemalloc(page); 1787 set_page_pfmemalloc(page);
1756 else 1788 else
1757 clear_page_pfmemalloc(page); 1789 clear_page_pfmemalloc(page);
1758
1759 return 0;
1760} 1790}
1761 1791
1762/* 1792/*
@@ -2178,6 +2208,9 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
2178 if (unlikely(page == NULL)) 2208 if (unlikely(page == NULL))
2179 break; 2209 break;
2180 2210
2211 if (unlikely(check_pcp_refill(page)))
2212 continue;
2213
2181 /* 2214 /*
2182 * Split buddy pages returned by expand() are received here 2215 * Split buddy pages returned by expand() are received here
2183 * in physical page order. The page is added to the callers and 2216 * in physical page order. The page is added to the callers and
@@ -2593,20 +2626,22 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
2593 struct list_head *list; 2626 struct list_head *list;
2594 2627
2595 local_irq_save(flags); 2628 local_irq_save(flags);
2596 pcp = &this_cpu_ptr(zone->pageset)->pcp; 2629 do {
2597 list = &pcp->lists[migratetype]; 2630 pcp = &this_cpu_ptr(zone->pageset)->pcp;
2598 if (list_empty(list)) { 2631 list = &pcp->lists[migratetype];
2599 pcp->count += rmqueue_bulk(zone, 0, 2632 if (list_empty(list)) {
2600 pcp->batch, list, 2633 pcp->count += rmqueue_bulk(zone, 0,
2601 migratetype, cold); 2634 pcp->batch, list,
2602 if (unlikely(list_empty(list))) 2635 migratetype, cold);
2603 goto failed; 2636 if (unlikely(list_empty(list)))
2604 } 2637 goto failed;
2638 }
2605 2639
2606 if (cold) 2640 if (cold)
2607 page = list_last_entry(list, struct page, lru); 2641 page = list_last_entry(list, struct page, lru);
2608 else 2642 else
2609 page = list_first_entry(list, struct page, lru); 2643 page = list_first_entry(list, struct page, lru);
2644 } while (page && check_new_pcp(page));
2610 2645
2611 __dec_zone_state(zone, NR_ALLOC_BATCH); 2646 __dec_zone_state(zone, NR_ALLOC_BATCH);
2612 list_del(&page->lru); 2647 list_del(&page->lru);
@@ -2619,14 +2654,16 @@ struct page *buffered_rmqueue(struct zone *preferred_zone,
2619 WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1)); 2654 WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
2620 spin_lock_irqsave(&zone->lock, flags); 2655 spin_lock_irqsave(&zone->lock, flags);
2621 2656
2622 page = NULL; 2657 do {
2623 if (alloc_flags & ALLOC_HARDER) { 2658 page = NULL;
2624 page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); 2659 if (alloc_flags & ALLOC_HARDER) {
2625 if (page) 2660 page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
2626 trace_mm_page_alloc_zone_locked(page, order, migratetype); 2661 if (page)
2627 } 2662 trace_mm_page_alloc_zone_locked(page, order, migratetype);
2628 if (!page) 2663 }
2629 page = __rmqueue(zone, order, migratetype); 2664 if (!page)
2665 page = __rmqueue(zone, order, migratetype);
2666 } while (page && check_new_pages(page, order));
2630 spin_unlock(&zone->lock); 2667 spin_unlock(&zone->lock);
2631 if (!page) 2668 if (!page)
2632 goto failed; 2669 goto failed;
@@ -2993,8 +3030,7 @@ try_this_zone:
2993 page = buffered_rmqueue(ac->preferred_zoneref->zone, zone, order, 3030 page = buffered_rmqueue(ac->preferred_zoneref->zone, zone, order,
2994 gfp_mask, alloc_flags, ac->migratetype); 3031 gfp_mask, alloc_flags, ac->migratetype);
2995 if (page) { 3032 if (page) {
2996 if (prep_new_page(page, order, gfp_mask, alloc_flags)) 3033 prep_new_page(page, order, gfp_mask, alloc_flags);
2997 goto try_this_zone;
2998 3034
2999 /* 3035 /*
3000 * If this is a high-order atomic allocation then check 3036 * If this is a high-order atomic allocation then check