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 11:57:23 +0530 [thread overview]
Message-ID: <4d5ae693-a9a5-4ed3-a881-ffef92145193@amd.com> (raw)
In-Reply-To: <9b0add60-9bca-44dc-a95d-be289ea2d3c1@amd.com>
Hi Matthew,
Ping ?
Regards,
Arun.
On 6/1/2026 4:21 PM, 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 ?
>>
>> 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.
>
>
next prev parent reply other threads:[~2026-06-10 6:27 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 [this message]
2026-06-10 9:19 ` Matthew Auld
2026-06-10 13:06 ` Arunpravin Paneer Selvam
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=4d5ae693-a9a5-4ed3-a881-ffef92145193@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