dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Arunpravin Paneer Selvam <arunpravin.paneerselvam@amd.com>
To: Matthew Auld <matthew.auld@intel.com>,
	christian.koenig@amd.com, dri-devel@lists.freedesktop.org,
	intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org,
	amd-gfx@lists.freedesktop.org
Cc: alexander.deucher@amd.com
Subject: Re: [PATCH v4 1/2] gpu/buddy: replace dual-tree/force_merge with decoupled clear tracker
Date: Wed, 10 Jun 2026 18:36:03 +0530	[thread overview]
Message-ID: <6ab93f55-0643-4518-9aaa-b12d55f8ccb4@amd.com> (raw)
In-Reply-To: <3ba98ec2-ea1f-4074-b1cc-456fca283ef8@intel.com>



On 6/10/2026 2:49 PM, Matthew Auld wrote:
> On 01/06/2026 11:51, Arunpravin Paneer Selvam wrote:
>>
>>
>> On 5/29/2026 11:11 PM, Matthew Auld wrote:
>>> Hi,
>>>
>>> On 27/05/2026 12:29, Arunpravin Paneer Selvam wrote:
>>>> The current buddy allocator maintains separate clear_tree[] and
>>>> dirty_tree[] rbtrees per order, preventing coalescing between cleared
>>>> and dirty buddies. Under mixed workloads, this creates a merge 
>>>> barrier:
>>>> adjacent buddies frequently end up split across trees, forcing 
>>>> reliance
>>>> on __force_merge() during allocation.
>>>>
>>>> __force_merge() performs an O(N x max_order) scan under the VRAM 
>>>> manager
>>>> lock, leading to allocation stalls and failures for large contiguous
>>>> requests even when sufficient total free memory is available.
>>>
>>> So is this contig with non power-of-two sizes?
>> Both power-of-two and non-power-of-two contiguous requests are 
>> affected - in either case, the required higher-order block can't form 
>> when its lower-order buddies are separated by clear/dirty state 
>> across the dual trees. But the core issue we are seeing is VRAM 
>> fragmentation caused by massive small allocations (e.g., thousands of 
>> 4 KiB–8 KiB buffers) that end up split across clear and dirty trees, 
>> preventing buddy coalescing. This leads to allocation failures and 
>> OOM in later workloads even when sufficient total free VRAM is 
>> available.
>>>
>>> Do we know if we could force_merge everything in one go or somehow 
>>> be more aggressive and do more than needed now, at the first sign of 
>>> contention here, instead of doing it piecemeal? Downside would be 
>>> losing more of the clear tracking, when this happens, but more re- 
>>> merging.
>>>
>>> Could we have another per-order list, of all blocks that we failed 
>>> to merge, when we did the free step? When doing the force merge 
>>> step, we maybe don't need to search blindly and can focus instead on 
>>> the stuff tracked in those lists? Maybe it doesn't need to be a 
>>> list, but could be another rb-tree?
>>>
>>> We know the size of the total allocation, if we trigger force_merge, 
>>> could we try to merge enough in one go for the entire allocation, 
>>> instead of restarting the entire thing on the next iteration? Would 
>>> that help at all?
>>>
>>> But I guess these are more for the stalling side, and won't help 
>>> much with the contig angle?
>> The memory is highly fragmented into mostly 4 KiB chunks and small 
>> scattered blocks across the dual trees, so although total free memory 
>> exists, it is split into low-order fragments. The workload then 
>> requests very large contiguous allocations (tens of GBs, e.g., ~64 
>> GiB), which fail with OOM because the allocator cannot form 
>> sufficiently large high- order blocks from the fragmented space. We 
>> could go with more aggressive merging or merge-in-one-go approaches, 
>> but this might waste more cleared memory. I think fundamentally the 
>> buddy allocator should be allowed to merge unconditionally - the 
>> single-tree approach with unconditional coalescing would improve the 
>> fragmentation and benefit contiguous allocations along with 
>> addressing the stalling and latency issues.
>>>
>>> For the extent idea, is there any merit in maybe doing this for all 
>>> contig blobs, and not just cleared stuff? Or is the workload you are 
>>> seeing only benefit users that want cleared stuff? Wondering if this 
>>> would benefit all users that want contig? Like if we hypothetically 
>>> kept clear and dirty separate, like we do now, but with an improved 
>>> force_merge, and then have extent tracking for all contig blobs and 
>>> replace the try_harder stuff? When you do a contig alloc, the 
>>> individual clear/dirty is still all there within the range, so you 
>>> can skip re-clearing in some cases. I guess downside is overall more 
>>> fuzzy contig + clear/free path, but I guess you would never get 
>>> allocation failures, when there is sufficient contig space?
>> Yes, extending extent tracking to all contig allocations has merit, 
>> but the core problem remains - with the dual-tree design, we still 
>> need force_merge to undo the clear/dirty split before those extents 
>> can form. In cases like heavy small-allocation workloads (thousands 
>> of 4 KiB buffers) running first, the memory ends up massively 
>> fragmented across both trees. When a very large contiguous allocation 
>> (e.g., ~64 GiB) comes in later, the allocator fails with OOM even 
>> though sufficient total free memory exists, because the extent 
>> tracker can't find a contiguous range that was never allowed to merge 
>> in the first place. I think the dirty/clear split is fundamentally 
>> the problem - allowing the buddy allocator to merge unconditionally 
>> removes this barrier, and the clear tracker can then be layered on 
>> top as an optimization without blocking coalescing.
>>>
>>>>
>>>> Solution
>>>>
>>>> Replace the dual-tree design with:
>>>> - A single free_tree[order] rbtree for dirty and mixed free blocks
>>>>    (fully cleared free blocks float outside this tree)
>>>> - A lightweight out-of-band clear tracker (gpu_clear_tracker)
>>>>
>>>> Fully cleared free blocks are tracked outside the buddy trees using an
>>>> augmented interval rbtree, enabling O(log E) lookup of the largest
>>>> cleared extents.
>>>>
>>>> Buddy coalescing is now unconditional in __gpu_buddy_free(), 
>>>> regardless
>>>> of clear/dirty state. This removes the merge barrier and eliminates 
>>>> the
>>>> need for __force_merge().
>>>>
>>>> Benefits
>>>>
>>>> - Correct high-order allocations after mixed clear/dirty workloads
>>>> - Elimination of O(N x max_order) merge cost from the allocation path
>>>> - O(log E) cleared-extent lookup replacing O(N) scans
>>>> - Predictable allocation latency under fragmentation
>>>> - Reduced complexity with a single tree per order
>>>
>>> Since there is no separate tracking for dirty stuff, is the non- 
>>> cleared alloc path a bit more "fuzzy" now, with it potentially 
>>> stealing cleared memory, or is it the same behaviour still?
>> Right, on v4, the dirty and mixed (partially cleared) blocks are 
>> allocated for the non-cleared alloc path, which can end up stealing 
>> cleared memory. On v5, I plan to address this with a three-tier dirty 
>> allocation fallback: dirty → mixed → clear, driven by rbtree augment 
>> bits (subtree_has_dirty, subtree_has_mixed), each pass O(log N). The 
>> split-descent also applies the same preference at every level when 
>> carving a higher-order block, so cleared memory is preserved as much 
>> as possible and only used as a last resort.
>> Thoughts ?
>
> No objections from me. Do you want me to still look at v4 in depth, or 
> wait for v5? I only really looked at this from high level.
I will send the v5. Please review the next version.

Thanks,
Arun.
>
>>>
>>> For drivers that don't use free tracking, is there some benefit? Are 
>>> there any downsides there? I assume that clear tracker is always empty.
>> Correct, for drivers that don't clear memory, the clear tracker is 
>> always empty and they simply allocate from the free_tree[]. Benefits:
>>
>> Single tree per order instead of dual trees (fewer rbtree operations)
>> No force_merge path at all (unconditional coalescing at free time)
>> Simpler code path overall
>>
>> No real downsides - the clear tracker adds zero overhead when empty, 
>> and the augment bits would simply show all blocks as dirty, so the 
>> walk degenerates to a normal rbtree lookup with no extra cost.
>>
>> Regards,
>> Arun.
>>
>>
>


  reply	other threads:[~2026-06-10 13:06 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-27 11:29 [PATCH v4 1/2] gpu/buddy: replace dual-tree/force_merge with decoupled clear tracker Arunpravin Paneer Selvam
2026-05-27 11:29 ` [PATCH v4 2/2] gpu/tests/buddy: add clear-tracker allocation latency benchmarks Arunpravin Paneer Selvam
2026-05-28 12:33 ` [PATCH v4 1/2] gpu/buddy: replace dual-tree/force_merge with decoupled clear tracker Arunpravin Paneer Selvam
2026-05-29 17:41 ` Matthew Auld
2026-06-01 10:51   ` Arunpravin Paneer Selvam
2026-06-10  6:27     ` Arunpravin Paneer Selvam
2026-06-10  9:19     ` Matthew Auld
2026-06-10 13:06       ` Arunpravin Paneer Selvam [this message]
2026-07-07 12:35         ` Arunpravin Paneer Selvam

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6ab93f55-0643-4518-9aaa-b12d55f8ccb4@amd.com \
    --to=arunpravin.paneerselvam@amd.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=matthew.auld@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox