From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from va-2-19.ptr.blmpb.com (va-2-19.ptr.blmpb.com [209.127.231.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D6CE422545 for ; Mon, 13 Jul 2026 13:17:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.127.231.19 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783948656; cv=none; b=kZeF3k1lqaqQO1XaV4ZI2ZQ4iAoMjluO/EPisxIXQc9bHd2bQ7sLusd+/bV9MZhJLSz0WYKfhGw5SGKNEDwuT+zeArYGvpNw9VUxY87eHvq9SkYWuH4XjA4BV46WfX26csTEOW+Ge/vSD+DOMTC6L81zN1e8Q4eiAdPW2N7igyU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783948656; c=relaxed/simple; bh=NVqCQPpCslxkIdddB4V+eUSrkSP8iprKS9ghT2L+91c=; h=Message-Id:Subject:Content-Type:Content-Disposition:Cc:From:Date: Mime-Version:To; b=BtSsKqxaQcVxrCEl5DRXSyeTH2/0N0cbxfd1JZTwDl8s2CUyD4/PyBeMThEB1cNkk4+KY8W0hDt8LnUlldmg8b8AnfN8oHYcGoZLnFloptQ7xK2qsRneWijAUp1dDXeC4ILqW9SrcLQ39mpgbtVcJuedYMBTTdrDz5BxCglyEO4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=picoheart.com; spf=pass smtp.mailfrom=picoheart.com; dkim=pass (2048-bit key) header.d=picoheart.com header.i=@picoheart.com header.b=IVDIch5s; arc=none smtp.client-ip=209.127.231.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=picoheart.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=picoheart.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=picoheart.com header.i=@picoheart.com header.b="IVDIch5s" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2604151535; d=picoheart.com; t=1783948639; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=HQryPrQFSPbWa2anbiX1aauRwBJAIVsu6Hx1hZ3u8hA=; b=IVDIch5sqQBnkCivGu4rn3gRCg8Y/+45QTggMK5xKt0e1yb/rSuDNS+6ed4+d2Lfhekl98 2LGxbaae+EDrv/Uir0+PrXPFsY+pcBfpoKzEdwGiHBJCWhpltGeCnn0qP92JMKXOiHLcGy K6MnQfn7AtZP3c8JSeBXQPZ1c8Q/aEsp+BWAuVHdbDm5owGuGKDhpGOY19XrYVE3KjL6ty g4ubf7Br9IhvOcDznPjJttP90hVTVbFTCqKzfpBALL87ix+HTQJykmioUXmITCvIhoQOIq HLWGrhbjSkefHWJlAdPjbRMEtnz1AG0M9dJMLZcKP/1iRk2YE/LiEwBORZ3WYQ== Message-Id: Subject: [PATCH v2] gpu: buddy: avoid repeated builds of root dfs when alloc range Content-Type: text/plain; charset=UTF-8 Received: from hostpc ([183.129.139.234]) by smtp.feishu.cn with ESMTPS; Mon, 13 Jul 2026 21:17:17 +0800 Content-Disposition: inline Content-Transfer-Encoding: 7bit Cc: , X-Lms-Return-Path: X-Original-From: Zhaoyu Liu From: "Zhaoyu Liu" Date: Mon, 13 Jul 2026 21:17:15 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 To: , , , , , The buddy allocator previously pre-built a DFS list by inserting all root blocks via list_add_tail() before every allocation call in __alloc_range_bias() and __gpu_buddy_alloc_range(). This is wasteful when the allocation can be satisfied by the first root or by sub-blocks produced from splits, as the remaining roots are never consumed. Introduce __get_candidate_block() which unifies the block acquisition logic for both __alloc_range_bias() and __alloc_range(): it first checks the DFS list (populated by splits during allocation or pre-filled by the caller for trim), and only when the list is exhausted does it lazily fetch the next root block through a cursor. When the caller pre-fills the DFS list (trim scenario), the cursor is initialized to mm->n_roots to disable root iteration entirely, preserving the original behavior. Signed-off-by: Zhaoyu Liu Suggested-by: Arun Pravin --- v2: - Change __get_candidate_block to inline - Link to v1: https://lore.kernel.org/all/ak+ECwsuSljmvyKd@hostpc/ --- drivers/gpu/buddy.c | 61 ++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index dc81fe0301ce..63b3959973fa 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -700,6 +700,41 @@ static void __gpu_buddy_undo_splits(struct gpu_buddy *mm, } } +/** + * __get_candidate_block - Get a candidate block for allocation. + * @mm: GPU buddy manager + * @dfs: List of candidate blocks. Populated in two ways: (1) pre-filled by + * the caller before allocation with blocks available for allocation, + * and (2) extended during allocation by block splits, which add the + * resulting sub-blocks for subsequent finer-grained allocation. + * @cursor: Pointer to current root index, advanced when iterating roots. + * Pass in a value >= mm->n_roots to disable root iteration entirely, + * restricting block acquisition to @dfs only; this is used in the + * trim scenario where only pre-split sub-blocks should be considered. + * + * Return: Pointer to the acquired block on success, ERR_PTR(-ENOSPC) when no + * more blocks are available. + */ +static inline struct gpu_buddy_block* +__get_candidate_block(struct gpu_buddy *mm, struct list_head *dfs, + uint32_t *cursor) +{ + struct gpu_buddy_block *block; + + block = list_first_entry_or_null(dfs, + struct gpu_buddy_block, + tmp_link); + if (block) { + list_del(&block->tmp_link); + return block; + } + + if (*cursor >= mm->n_roots) + return ERR_PTR(-ENOSPC); + + return mm->roots[(*cursor)++]; +} + static struct gpu_buddy_block * __alloc_range_bias(struct gpu_buddy *mm, u64 start, u64 end, @@ -711,25 +746,18 @@ __alloc_range_bias(struct gpu_buddy *mm, struct gpu_buddy_block *block; LIST_HEAD(dfs); int err; - int i; + uint32_t cursor = 0; end = end - 1; - for (i = 0; i < mm->n_roots; ++i) - list_add_tail(&mm->roots[i]->tmp_link, &dfs); - do { u64 block_start; u64 block_end; - block = list_first_entry_or_null(&dfs, - struct gpu_buddy_block, - tmp_link); - if (!block) + block = __get_candidate_block(mm, &dfs, &cursor); + if (IS_ERR(block)) break; - list_del(&block->tmp_link); - if (gpu_buddy_block_order(block) < order) continue; @@ -1023,6 +1051,7 @@ static int __alloc_range(struct gpu_buddy *mm, LIST_HEAD(allocated); u64 end; int err; + uint32_t cursor = list_empty(dfs) ? 0 : mm->n_roots; end = start + size - 1; @@ -1030,14 +1059,10 @@ static int __alloc_range(struct gpu_buddy *mm, u64 block_start; u64 block_end; - block = list_first_entry_or_null(dfs, - struct gpu_buddy_block, - tmp_link); - if (!block) + block = __get_candidate_block(mm, dfs, &cursor); + if (IS_ERR(block)) break; - list_del(&block->tmp_link); - block_start = gpu_buddy_block_offset(block); block_end = block_start + gpu_buddy_block_size(mm, block) - 1; @@ -1109,10 +1134,6 @@ static int __gpu_buddy_alloc_range(struct gpu_buddy *mm, struct list_head *blocks) { LIST_HEAD(dfs); - int i; - - for (i = 0; i < mm->n_roots; ++i) - list_add_tail(&mm->roots[i]->tmp_link, &dfs); return __alloc_range(mm, &dfs, start, size, blocks, total_allocated_on_err); -- 2.34.1