Skip to content

Commit 5c1f4e6

Browse files
urezkitorvalds
authored andcommitted
mm/vmalloc: switch to bulk allocator in __vmalloc_area_node()
Recently there has been introduced a page bulk allocator for users which need to get number of pages per one call request. For order-0 pages switch to an alloc_pages_bulk_array_node() instead of alloc_pages_node(), the reason is the former is not capable of allocating set of pages, thus a one call is per one page. Second, according to my tests the bulk allocator uses less cycles even for scenarios when only one page is requested. Running the "perf" on same test case shows below difference: <default> - 45.18% __vmalloc_node - __vmalloc_node_range - 35.60% __alloc_pages - get_page_from_freelist 3.36% __list_del_entry_valid 3.00% check_preemption_disabled 1.42% prep_new_page <default> <patch> - 31.00% __vmalloc_node - __vmalloc_node_range - 14.48% __alloc_pages_bulk 3.22% __list_del_entry_valid - 0.83% __alloc_pages get_page_from_freelist <patch> The "test_vmalloc.sh" also shows performance improvements: fix_size_alloc_test_4MB loops: 1000000 avg: 89105095 usec fix_size_alloc_test loops: 1000000 avg: 513672 usec full_fit_alloc_test loops: 1000000 avg: 748900 usec long_busy_list_alloc_test loops: 1000000 avg: 8043038 usec random_size_alloc_test loops: 1000000 avg: 4028582 usec fix_align_alloc_test loops: 1000000 avg: 1457671 usec fix_size_alloc_test_4MB loops: 1000000 avg: 62083711 usec fix_size_alloc_test loops: 1000000 avg: 449207 usec full_fit_alloc_test loops: 1000000 avg: 735985 usec long_busy_list_alloc_test loops: 1000000 avg: 5176052 usec random_size_alloc_test loops: 1000000 avg: 2589252 usec fix_align_alloc_test loops: 1000000 avg: 1365009 usec For example 4MB allocations illustrates ~30% gain, all the rest is also better. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Uladzislau Rezki (Sony) <[email protected]> Acked-by: Mel Gorman <[email protected]> Cc: Hillf Danton <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Nicholas Piggin <[email protected]> Cc: Oleksiy Avramchenko <[email protected]> Cc: Steven Rostedt <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent a2afc59 commit 5c1f4e6

File tree

1 file changed

+42
-34
lines changed

1 file changed

+42
-34
lines changed

mm/vmalloc.c

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,8 +2768,6 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
27682768
unsigned long array_size;
27692769
unsigned int nr_small_pages = size >> PAGE_SHIFT;
27702770
unsigned int page_order;
2771-
struct page **pages;
2772-
unsigned int i;
27732771

27742772
array_size = (unsigned long)nr_small_pages * sizeof(struct page *);
27752773
gfp_mask |= __GFP_NOWARN;
@@ -2778,13 +2776,13 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
27782776

27792777
/* Please note that the recursion is strictly bounded. */
27802778
if (array_size > PAGE_SIZE) {
2781-
pages = __vmalloc_node(array_size, 1, nested_gfp, node,
2779+
area->pages = __vmalloc_node(array_size, 1, nested_gfp, node,
27822780
area->caller);
27832781
} else {
2784-
pages = kmalloc_node(array_size, nested_gfp, node);
2782+
area->pages = kmalloc_node(array_size, nested_gfp, node);
27852783
}
27862784

2787-
if (!pages) {
2785+
if (!area->pages) {
27882786
free_vm_area(area);
27892787
warn_alloc(gfp_mask, NULL,
27902788
"vmalloc size %lu allocation failure: "
@@ -2793,43 +2791,53 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
27932791
return NULL;
27942792
}
27952793

2796-
area->pages = pages;
2797-
area->nr_pages = nr_small_pages;
2794+
area->nr_pages = 0;
27982795
set_vm_area_page_order(area, page_shift - PAGE_SHIFT);
2799-
28002796
page_order = vm_area_page_order(area);
28012797

2802-
/*
2803-
* Careful, we allocate and map page_order pages, but tracking is done
2804-
* per PAGE_SIZE page so as to keep the vm_struct APIs independent of
2805-
* the physical/mapped size.
2806-
*/
2807-
for (i = 0; i < area->nr_pages; i += 1U << page_order) {
2808-
struct page *page;
2809-
int p;
2810-
2811-
/* Compound pages required for remap_vmalloc_page */
2812-
page = alloc_pages_node(node, gfp_mask | __GFP_COMP, page_order);
2813-
if (unlikely(!page)) {
2814-
/* Successfully allocated i pages, free them in __vfree() */
2815-
area->nr_pages = i;
2816-
atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
2817-
warn_alloc(gfp_mask, NULL,
2818-
"vmalloc size %lu allocation failure: "
2819-
"page order %u allocation failed",
2820-
area->nr_pages * PAGE_SIZE, page_order);
2821-
goto fail;
2822-
}
2798+
if (!page_order) {
2799+
area->nr_pages = alloc_pages_bulk_array_node(
2800+
gfp_mask, node, nr_small_pages, area->pages);
2801+
} else {
2802+
/*
2803+
* Careful, we allocate and map page_order pages, but tracking is done
2804+
* per PAGE_SIZE page so as to keep the vm_struct APIs independent of
2805+
* the physical/mapped size.
2806+
*/
2807+
while (area->nr_pages < nr_small_pages) {
2808+
struct page *page;
2809+
int i;
2810+
2811+
/* Compound pages required for remap_vmalloc_page */
2812+
page = alloc_pages_node(node, gfp_mask | __GFP_COMP, page_order);
2813+
if (unlikely(!page))
2814+
break;
28232815

2824-
for (p = 0; p < (1U << page_order); p++)
2825-
area->pages[i + p] = page + p;
2816+
for (i = 0; i < (1U << page_order); i++)
2817+
area->pages[area->nr_pages + i] = page + i;
28262818

2827-
if (gfpflags_allow_blocking(gfp_mask))
2828-
cond_resched();
2819+
if (gfpflags_allow_blocking(gfp_mask))
2820+
cond_resched();
2821+
2822+
area->nr_pages += 1U << page_order;
2823+
}
28292824
}
2825+
28302826
atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
28312827

2832-
if (vmap_pages_range(addr, addr + size, prot, pages, page_shift) < 0) {
2828+
/*
2829+
* If not enough pages were obtained to accomplish an
2830+
* allocation request, free them via __vfree() if any.
2831+
*/
2832+
if (area->nr_pages != nr_small_pages) {
2833+
warn_alloc(gfp_mask, NULL,
2834+
"vmalloc size %lu allocation failure: "
2835+
"page order %u allocation failed",
2836+
area->nr_pages * PAGE_SIZE, page_order);
2837+
goto fail;
2838+
}
2839+
2840+
if (vmap_pages_range(addr, addr + size, prot, area->pages, page_shift) < 0) {
28332841
warn_alloc(gfp_mask, NULL,
28342842
"vmalloc size %lu allocation failure: "
28352843
"failed to map pages",

0 commit comments

Comments
 (0)