vmem_chunked: `reuse()` rollback skips free-listed blocks, leaving the heap fragmented
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- Half a day
- Newbie friendliness
- 58/100
Research direction
Start with VMemChunkedAllocator.reuse() and collect(), and check how _released, bump and free_lists interact. Read test_chunked_churn_then_large_allocation_does_not_grow and run it with the keep_every=16 case. Done when the extended test frees all kept buffers, reclaims them, allocates most of the heap, and get_num_chunks() stays unchanged. Keep the free-list state identical on every rank.
Written by the indexing model from the issue text.
Description
VMemChunkedAllocator.reuse() (added in #583) returns freed blocks at the top of the heap to the bump pointer, but it only considers blocks released in the current collect(). Blocks that went to a free list in an earlier round are never rolled back, even after the blocks above them are freed. The heap then stays split into small size-class blocks, and a later large allocation grows the heap even though the space below bump is free.
This behavior predates #583 (the allocator never merged free blocks), so it isn't a regression. It came up in review and was deferred to keep #583's scope: https://github.com/ROCm/iris/pull/583#discussion_r4275470909
How it happens
round k: [ s1 ][ s2 ][ K ][ s3 ] <- bump K = long-lived buffer, still in use
s3 rolls back; s1 and s2 go to a free list (K blocks the rollback)
round k+1: [ s1 ][ s2 ][ K ] <- bump K is freed and rolls back
the rollback stops: s2 ends at bump, but it's on a free list, not among this round's offsets
Bookkeeping model (agent-assisted; pure Python, no GPU): the shape of test_chunked_churn_then_large_allocation_does_not_grow with keep_every=16 at 4 KB granularity, then all kept buffers freed, then a 48 MB allocation in the 64 MB heap.
| heap growths during the 48 MB allocation | |
|---|---|
| before #583 | 1 |
| after #583 | 1 |
| with the change below | 0 |
Proposed change
Treat free-listed blocks as rollback candidates in reuse():
with self.lock:
self._bytes_since_collect = 0
candidates = {offset: self._released.pop(offset) for offset in offsets}
# Blocks freed in earlier rounds can reach the top once the blocks above them are freed
for size_class, free in self.free_lists.items():
candidates.update((offset, size_class) for offset in free)
free.clear()
# Blocks at the top of the bump region go back to the bump pointer, not a size class
by_end = {offset + size: offset for offset, size in candidates.items()}
while self.bump in by_end:
self.bump = by_end.pop(self.bump)
del candidates[self.bump]
for offset in sorted(candidates):
self.free_lists[candidates[offset]].append(offset)
- Stays symmetric across ranks: both inputs, the intersection passed by
collect()andfree_lists, are identical on every rank. - Cost: O(F log F) per
collect()for F free blocks, small next to thegc.collect()and device synccollect()already does. - Optional: append in descending order (
sorted(candidates, reverse=True)) sopop()hands out the lowest offsets first, keeping blocks near the top free for later rollbacks.
Test
Extend test_chunked_churn_then_large_allocation_does_not_grow (keep_every=16 case): after the loop, kept.clear() and ctx.reclaim_freed(), then allocate most of the heap and assert get_num_chunks() is unchanged.
- Dominant language
- Python
- Stars
- 202
- Forks
- 52
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 23
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- Ships a Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ROCm/iris
-
core examples good first issue help wanted iris python
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 2 days
-
benchmarks bug examples iris test
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 2 days
-
bug examples invalid iris
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 2 days
-
enhancement gluon help wanted iris
Difficulty 5/5 Over a week Newbie friendliness 18/100
Maintainers usually reply within 2 days
-
good first issue help wanted iris
Difficulty 3/5 Half a day Newbie friendliness 62/100
Maintainers usually reply within 2 days
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
UKGovernmentBEIS/control-arena#917 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
debpalash/VoiceStudio#2937 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
aws-samples/sample-per-model-bedrock#261 ·
Maintainers usually reply within 1 day