Skip to content

Commit 066b239

Browse files
gormanmtorvalds
authored andcommitted
mm, page_alloc: split buffered_rmqueue()
Patch series "Use per-cpu allocator for !irq requests and prepare for a bulk allocator", v5. This series is motivated by a conversation led by Jesper Dangaard Brouer at the last LSF/MM proposing a generic page pool for DMA-coherent pages. Part of his motivation was due to the overhead of allocating multiple order-0 that led some drivers to use high-order allocations and splitting them. This is very slow in some cases. The first two patches in this series restructure the page allocator such that it is relatively easy to introduce an order-0 bulk page allocator. A patch exists to do that and has been handed over to Jesper until an in-kernel users is created. The third patch prevents the per-cpu allocator being drained from IPI context as that can potentially corrupt the list after patch four is merged. The final patch alters the per-cpu alloctor to make it exclusive to !irq requests. This cuts allocation/free overhead by roughly 30%. Performance tests from both Jesper and me are included in the patch. This patch (of 4): buffered_rmqueue removes a page from a given zone and uses the per-cpu list for order-0. This is fine but a hypothetical caller that wanted multiple order-0 pages has to disable/reenable interrupts multiple times. This patch structures buffere_rmqueue such that it's relatively easy to build a bulk order-0 page allocator. There is no functional change. [[email protected]: failed per-cpu refill may blow up] Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Mel Gorman <[email protected]> Acked-by: Hillf Danton <[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 c55e8d0 commit 066b239

File tree

1 file changed

+79
-49
lines changed

1 file changed

+79
-49
lines changed

mm/page_alloc.c

Lines changed: 79 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,74 +2600,104 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)
26002600
#endif
26012601
}
26022602

2603+
/* Remove page from the per-cpu list, caller must protect the list */
2604+
static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,
2605+
bool cold, struct per_cpu_pages *pcp,
2606+
struct list_head *list)
2607+
{
2608+
struct page *page;
2609+
2610+
do {
2611+
if (list_empty(list)) {
2612+
pcp->count += rmqueue_bulk(zone, 0,
2613+
pcp->batch, list,
2614+
migratetype, cold);
2615+
if (unlikely(list_empty(list)))
2616+
return NULL;
2617+
}
2618+
2619+
if (cold)
2620+
page = list_last_entry(list, struct page, lru);
2621+
else
2622+
page = list_first_entry(list, struct page, lru);
2623+
2624+
list_del(&page->lru);
2625+
pcp->count--;
2626+
} while (check_new_pcp(page));
2627+
2628+
return page;
2629+
}
2630+
2631+
/* Lock and remove page from the per-cpu list */
2632+
static struct page *rmqueue_pcplist(struct zone *preferred_zone,
2633+
struct zone *zone, unsigned int order,
2634+
gfp_t gfp_flags, int migratetype)
2635+
{
2636+
struct per_cpu_pages *pcp;
2637+
struct list_head *list;
2638+
bool cold = ((gfp_flags & __GFP_COLD) != 0);
2639+
struct page *page;
2640+
unsigned long flags;
2641+
2642+
local_irq_save(flags);
2643+
pcp = &this_cpu_ptr(zone->pageset)->pcp;
2644+
list = &pcp->lists[migratetype];
2645+
page = __rmqueue_pcplist(zone, migratetype, cold, pcp, list);
2646+
if (page) {
2647+
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
2648+
zone_statistics(preferred_zone, zone);
2649+
}
2650+
local_irq_restore(flags);
2651+
return page;
2652+
}
2653+
26032654
/*
26042655
* Allocate a page from the given zone. Use pcplists for order-0 allocations.
26052656
*/
26062657
static inline
2607-
struct page *buffered_rmqueue(struct zone *preferred_zone,
2658+
struct page *rmqueue(struct zone *preferred_zone,
26082659
struct zone *zone, unsigned int order,
26092660
gfp_t gfp_flags, unsigned int alloc_flags,
26102661
int migratetype)
26112662
{
26122663
unsigned long flags;
26132664
struct page *page;
2614-
bool cold = ((gfp_flags & __GFP_COLD) != 0);
26152665

26162666
if (likely(order == 0)) {
2617-
struct per_cpu_pages *pcp;
2618-
struct list_head *list;
2619-
2620-
local_irq_save(flags);
2621-
do {
2622-
pcp = &this_cpu_ptr(zone->pageset)->pcp;
2623-
list = &pcp->lists[migratetype];
2624-
if (list_empty(list)) {
2625-
pcp->count += rmqueue_bulk(zone, 0,
2626-
pcp->batch, list,
2627-
migratetype, cold);
2628-
if (unlikely(list_empty(list)))
2629-
goto failed;
2630-
}
2631-
2632-
if (cold)
2633-
page = list_last_entry(list, struct page, lru);
2634-
else
2635-
page = list_first_entry(list, struct page, lru);
2636-
2637-
list_del(&page->lru);
2638-
pcp->count--;
2667+
page = rmqueue_pcplist(preferred_zone, zone, order,
2668+
gfp_flags, migratetype);
2669+
goto out;
2670+
}
26392671

2640-
} while (check_new_pcp(page));
2641-
} else {
2642-
/*
2643-
* We most definitely don't want callers attempting to
2644-
* allocate greater than order-1 page units with __GFP_NOFAIL.
2645-
*/
2646-
WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
2647-
spin_lock_irqsave(&zone->lock, flags);
2672+
/*
2673+
* We most definitely don't want callers attempting to
2674+
* allocate greater than order-1 page units with __GFP_NOFAIL.
2675+
*/
2676+
WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
2677+
spin_lock_irqsave(&zone->lock, flags);
26482678

2649-
do {
2650-
page = NULL;
2651-
if (alloc_flags & ALLOC_HARDER) {
2652-
page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
2653-
if (page)
2654-
trace_mm_page_alloc_zone_locked(page, order, migratetype);
2655-
}
2656-
if (!page)
2657-
page = __rmqueue(zone, order, migratetype);
2658-
} while (page && check_new_pages(page, order));
2659-
spin_unlock(&zone->lock);
2679+
do {
2680+
page = NULL;
2681+
if (alloc_flags & ALLOC_HARDER) {
2682+
page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
2683+
if (page)
2684+
trace_mm_page_alloc_zone_locked(page, order, migratetype);
2685+
}
26602686
if (!page)
2661-
goto failed;
2662-
__mod_zone_freepage_state(zone, -(1 << order),
2663-
get_pcppage_migratetype(page));
2664-
}
2687+
page = __rmqueue(zone, order, migratetype);
2688+
} while (page && check_new_pages(page, order));
2689+
spin_unlock(&zone->lock);
2690+
if (!page)
2691+
goto failed;
2692+
__mod_zone_freepage_state(zone, -(1 << order),
2693+
get_pcppage_migratetype(page));
26652694

26662695
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
26672696
zone_statistics(preferred_zone, zone);
26682697
local_irq_restore(flags);
26692698

2670-
VM_BUG_ON_PAGE(bad_range(zone, page), page);
2699+
out:
2700+
VM_BUG_ON_PAGE(page && bad_range(zone, page), page);
26712701
return page;
26722702

26732703
failed:
@@ -2972,7 +3002,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
29723002
}
29733003

29743004
try_this_zone:
2975-
page = buffered_rmqueue(ac->preferred_zoneref->zone, zone, order,
3005+
page = rmqueue(ac->preferred_zoneref->zone, zone, order,
29763006
gfp_mask, alloc_flags, ac->migratetype);
29773007
if (page) {
29783008
prep_new_page(page, order, gfp_mask, alloc_flags);

0 commit comments

Comments
 (0)