On Tue, 14 Oct 2025 16:32:30 +0800 "zhaoyang.huang" <[email protected]> wrote:
> From: Zhaoyang Huang <[email protected]> > > The size of once dma-buf allocation could be dozens MB or much more > which introduce a loop of allocating several thousands of order-0 pages. > Furthermore, the concurrent allocation could have dma-buf allocation enter > direct-reclaim during the loop. This commit would like to eliminate the > above two affections by introducing alloc_pages_bulk_list in dma-buf's > order-0 allocation. This patch is proved to be conditionally helpful > in 18MB allocation as decreasing the time from 24604us to 6555us and no > harm when bulk allocation can't be done(fallback to single page > allocation) > > Signed-off-by: Zhaoyang Huang <[email protected]> > --- > drivers/dma-buf/heaps/system_heap.c | 36 +++++++++++++++++++---------- > 1 file changed, 24 insertions(+), 12 deletions(-) > > diff --git a/drivers/dma-buf/heaps/system_heap.c > b/drivers/dma-buf/heaps/system_heap.c > index bbe7881f1360..71b028c63bd8 100644 > --- a/drivers/dma-buf/heaps/system_heap.c > +++ b/drivers/dma-buf/heaps/system_heap.c > @@ -300,8 +300,8 @@ static const struct dma_buf_ops system_heap_buf_ops = { > .release = system_heap_dma_buf_release, > }; > > -static struct page *alloc_largest_available(unsigned long size, > - unsigned int max_order) > +static void alloc_largest_available(unsigned long size, > + unsigned int max_order, unsigned int *num_pages, struct > list_head *list) This interface feels weird. Maybe you could return the number of pages instead of making this a void function and passing a pointer to get that number? > { > struct page *page; > int i; > @@ -312,12 +312,19 @@ static struct page *alloc_largest_available(unsigned > long size, > if (max_order < orders[i]) > continue; > > - page = alloc_pages(order_flags[i], orders[i]); > - if (!page) > + if (orders[i]) { > + page = alloc_pages(order_flags[i], orders[i]); nitpick: Since the lowest order is special-cased now, you can simply use HIGH_ORDER_GFP here and remove order_flags[] entirely. > + if (page) { > + list_add(&page->lru, list); > + *num_pages = 1; > + } > + } else > + *num_pages = alloc_pages_bulk_list(LOW_ORDER_GFP, size > / PAGE_SIZE, list); > + > + if (list_empty(list)) > continue; > - return page; > + return; > } > - return NULL; > } > > static struct dma_buf *system_heap_allocate(struct dma_heap *heap, > @@ -335,6 +342,8 @@ static struct dma_buf *system_heap_allocate(struct > dma_heap *heap, > struct list_head pages; > struct page *page, *tmp_page; > int i, ret = -ENOMEM; > + unsigned int num_pages; > + LIST_HEAD(head); > > buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); > if (!buffer) > @@ -348,6 +357,8 @@ static struct dma_buf *system_heap_allocate(struct > dma_heap *heap, > INIT_LIST_HEAD(&pages); > i = 0; > while (size_remaining > 0) { > + num_pages = 0; > + INIT_LIST_HEAD(&head); > /* > * Avoid trying to allocate memory if the process > * has been killed by SIGKILL > @@ -357,14 +368,15 @@ static struct dma_buf *system_heap_allocate(struct > dma_heap *heap, > goto free_buffer; > } > > - page = alloc_largest_available(size_remaining, max_order); > - if (!page) > + alloc_largest_available(size_remaining, max_order, &num_pages, > &head); > + if (!num_pages) > goto free_buffer; > > - list_add_tail(&page->lru, &pages); > - size_remaining -= page_size(page); > - max_order = compound_order(page); > - i++; > + list_splice_tail(&head, &pages); > + max_order = folio_order(lru_to_folio(&head)); > + size_remaining -= PAGE_SIZE * (num_pages << max_order); This looks complicated. What about changing alloc_largest_available() to return the total number of pages and using PAGE_SIZE * num_page? Ah, you still have to look at the folio order to determine the new value of max_order, so no big win. Hm. You could pass a pointer to max_order down to alloc_largest_available(), but at that point I think it's a matter of taste (aka bikeshedding). Petr T > + i += num_pages; > + > } > > table = &buffer->sg_table;
