Skip to content

Fix conform request in the Vulkan memory allocator to avoid rounding up on subsequent passes.#9223

Open
johningve wants to merge 5 commits into
halide:mainfrom
johningve:vulkan-allocator-fixes
Open

Fix conform request in the Vulkan memory allocator to avoid rounding up on subsequent passes.#9223
johningve wants to merge 5 commits into
halide:mainfrom
johningve:vulkan-allocator-fixes

Conversation

@johningve

@johningve johningve commented Jul 20, 2026

Copy link
Copy Markdown

This PR fixes two bugs in the vulkan memory allocator, both related to conform. I ran into these issues when testing out the Vulkan backend with Mesa (llvmpipe / RADV).

One of the bugs was already reported: #8868

I did not add any tests because I could not see any existing tests for the Vulkan-specific runtime internals, and coming up with a test strategy for this is not something I feel prepared to do at this point since I'm new to the project.

I used Claude to help root-cause the bugs and then implemented the fixes myself.

Checklist

  • Tests added or updated (not required for docs, CI config, or typo fixes)
  • Documentation updated (if public API changed)
  • Python bindings updated (if public API changed)
  • Benchmarks are included here if the change is intended to affect performance.
  • Commits include AI attribution where applicable (see Code of Conduct)

johningve and others added 2 commits July 20, 2026 13:10
conform() used request->alignment to decide whether to raise the
region's nearest_multiple, but it also writes the conformed alignment
back into the request. Therefore, conforming an already-conformed
request can produce a larger size because the second pass sees a larger
request->alignment and decides to raise the nearest_multiple.

The conform method of the vulkan memory allocator is called by the
runtime block allocator on multiple levels, using requests that were
already conformed, so different layers see mismatching sizes.

The mismatch causes issues observable on drivers reporting 64-byte
buffer alignment (Mesa lavapipe/RADV): a 96-byte buffer gets a 64-byte
region, and the transfer overruns it. The Khronos validation layer flags
it as VUID-vkCmdCopyBuffer-size-00115/00116 ("size (96) is greater than
the buffer size (64)"). These errors are present before this commit and
gone after it.

This commit changes conform() to use the conformed alignment instead of
request->alignment, to decide whether to raise nearest_multiple.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Previously it was possible that a region's conformed size exceeded the
conformed size of its block. This could happen because a block's size
was conformed by conform_block_request (rounding to the config
nearest_multiple, then overwriting with VkMemoryRequirements.size),
while regions carved from the block were conformed by a separate path
that also rounds up to the device buffer alignment. The two paths
disagree: for a buffer whose size is a multiple of the config
nearest_multiple but not of the device alignment, the block was sized
smaller than the region request it had to hold.

On drivers reporting 64-byte buffer alignment (Mesa lavapipe/RADV), a
9338976-byte buffer (a multiple of 32 but not 64) produced a
9338976-byte block, while the region inside it conformed to 9339008.
RegionAllocator::reserve then failed its headroom check, collect()
retried, a second block failed identically, and allocation failed with
"Failed to allocate device memory!".

This commit fixes the issue by factoring the request-conforming
arithmetic into a shared helper and calling it from both the block and
region conform paths, so a block is always sized to hold a conformed
region request of the same size.

Fixes halide#8868

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@johningve johningve mentioned this pull request Jul 20, 2026
5 tasks
@derek-gerstmann derek-gerstmann changed the title Fix bugs in the Vulkan memory allocator Fix conform request in the Vulkan memory allocator to avoid rounding up on subsequent passes. Jul 20, 2026

@derek-gerstmann derek-gerstmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much for the contribution! Yes, the conform request cleary should not be rounding up to the next nearest multiple on subsequent passes after the alignment is already adjusted.

Since the Vulkan Memory Allocator uses the block allocator interface, could you add some test cases to the runtime/internal tests for the block_allocator/region_allocator?

Comment thread src/runtime/vulkan_memory.h Outdated
size_t actual_alignment = conform_alignment(request->alignment, memory_requirements->alignment);

// Ensure the request ends on an aligned address.
// NOTE: use the conformed alignment and not the input alignment. Otherwise, conform is not idempotent:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, good catch! Yes, the block allocator assumes that the conform is idempotent, and it shouldn't be rounding up to the next greatest multiple on subsequent passes if the alignment is already conformed.

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@34f0771). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9223   +/-   ##
=======================================
  Coverage        ?   69.64%           
=======================================
  Files           ?      255           
  Lines           ?    78885           
  Branches        ?    18859           
=======================================
  Hits            ?    54941           
  Misses          ?    18300           
  Partials        ?     5644           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

johningve and others added 3 commits July 21, 2026 11:19
This commit moves the conform implementation from the vulkan_memory.h
header into the memory_resources.h header so that it can be tested by
the runtime/internal block+region allocator test.

A test case is added to check that conform is idempotent over a number
of different inputs, as well as testing the specific values from drivers
reporting 64-bit alignment that revealed the previous version of conform
to not be idempotent.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The error messages in allocate_block say "unable to deallocate". Likely
copy-pasted from deallcate_block.
The debug print of find_block_region has block->memory.allocation.size.
But this does not compile. block->memory has a size member itself, so
use that instead.
@johningve
johningve force-pushed the vulkan-allocator-fixes branch from 6baa469 to 07c6b6c Compare July 21, 2026 09:20
@johningve

Copy link
Copy Markdown
Author

Thanks very much for the contribution! Yes, the conform request cleary should not be rounding up to the next nearest multiple on subsequent passes after the alignment is already adjusted.

Since the Vulkan Memory Allocator uses the block allocator interface, could you add some test cases to the runtime/internal tests for the block_allocator/region_allocator?

I added a commit that moves the conform function into memory_resources.h so that it can be used in the runtime/internal test:

[vulkan] Move conform implementation to memory_resources.h and add tests
36cdf2a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants