Skip to content

Prefer cached host memory for readback allocations - #42

Merged
conda-forge-admin merged 2 commits into
conda-forge:mainfrom
hmaarrfk:prefer_cached_host_memory_for_readback
Aug 20, 2026
Merged

Prefer cached host memory for readback allocations#42
conda-forge-admin merged 2 commits into
conda-forge:mainfrom
hmaarrfk:prefer_cached_host_memory_for_readback

Conversation

@hmaarrfk

@hmaarrfk hmaarrfk commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Readback (MemoryLocation::GpuToCpu) allocations land on uncached memory on Intel iGPUs since wgpu v28, making CPU reads of mapped buffers about 100x slower than RAM. This carries a one-hunk fix in gpu-allocator until it can be upstreamed.

Mechanism

wgpu v28 switched the Vulkan backend from gpu-alloc to gpu-allocator (gfx-rs/wgpu#8158). gpu-allocator's GpuToCpu path tries HOST_VISIBLE|HOST_COHERENT|HOST_CACHED, then falls back to HOST_VISIBLE|HOST_COHERENT — both require HOST_COHERENT. Intel's ANV on Arrow Lake exposes cached memory and coherent memory but never both, so every readback allocation lands on the uncached (write-combined) type. gpu-alloc scored HOST_CACHED as a preference rather than a requirement, which is why this only appears from v28 on.

Measured on one VkDevice, one heap, Arrow Lake iGPU — allocating from each host-visible type and timing an 8 MiB CPU read:

type 0  DEVICE_LOCAL|HOST_VISIBLE|COHERENT    0.27 GB/s   <- what gpu-allocator picks
type 1  DEVICE_LOCAL|HOST_VISIBLE|CACHED     25.06 GB/s   <- what the patch picks

The patch adds one attempt between the two that already exist: try HOST_VISIBLE|HOST_CACHED before giving up and taking a coherent-but-uncached type. It is safe because wgpu-hal already keys flush_mapped_ranges/invalidate_mapped_ranges off the allocation's real property flags (vulkan/device.rs:993), so non-coherent memory is fully supported — it was simply never selected.

Effect

Same machine, same Mesa, only the library differing (8.29 MB mapped read):

wgpu-native time throughput
27.0.4.0 (pre-switch) 0.33 ms 25.22 GB/s
29.0.1.1 stock 30.90 ms 0.27 GB/s
29.0.1.1 + this patch 0.33 ms 25.22 GB/s

Confirmed on a second Arrow Lake machine on a different Mesa (25.2.8): 24.45 GB/s on 27, 0.23 GB/s on 29 stock, 24.59 GB/s on 29 + patch — so this tracks the adapter's memory types, not the driver version. A Tiger Lake iGPU is unaffected either way because it does expose a COHERENT|CACHED type, as are all NVIDIA adapters for the same reason. A standalone Rust reproducer against the wgpu crate puts the boundary at v28.0.0 exactly (v27.0.1 = 1.0x, v28.0.0 = 86.6x, v29.0.4 = 86.4x).

Why gpu-allocator is vendored as a second source

gpu-allocator is pulled from crates.io during cargo build, so a feedstock patch cannot otherwise reach it. Adding it as a second source: with a [patch.crates-io] override is the only way to carry the fix without forking wgpu-native itself. The vendored version (0.28.0) and its sha256 match what wgpu-native's committed Cargo.lock already resolves, so the dependency graph is unchanged apart from the patch.

Two conda-build details worth flagging for review:

  • The crate is fetched with fn: set to a .tar.gz name. A .crate file is a gzipped tarball, but conda-build dispatches extraction on the file extension and .crate is not in its decompressible_exts, so without this it is copied into the source tree rather than unpacked and the patch has nothing to apply to.
  • [patch.crates-io] is honored because wgpu-native's Cargo.toml is itself the workspace root ([workspace] members = ["."]).

This should be upstreamed and removed

Submitted upstream as Traverse-Research/gpu-allocator#311. The patch is intended to be dropped as soon as it lands there, and the extra source: entry and the [patch.crates-io] patch go with it. This is a temporary carry, not a permanent feedstock divergence.

What is not tested

Measured on Linux/x86_64 with Intel and NVIDIA adapters. Windows, macOS/Metal and AMD were not tested. The patch only affects the Vulkan path's GpuToCpu memory-type search; on adapters that expose a coherent+cached type the new branch never executes, and on non-Vulkan backends it is not reached at all.

Checklist

  • Used a personal fork of the feedstock to propose changes
  • Bumped the build number (if the version is unchanged)
  • Reset the build number to 0 (if the version changed) — n/a, version unchanged
  • Re-rendered with the latest conda-smithy — done by the webservices bot on this branch.
  • Ensured the license file is being packaged

@conda-forge-admin

Copy link
Copy Markdown
Contributor

Hi! This is the friendly automated conda-forge-linting service.

I just wanted to let you know that I linted all conda-recipes in your PR (recipe/meta.yaml) and found it was in an excellent condition.

@hmaarrfk

Copy link
Copy Markdown
Contributor Author

@hmaarrfk
hmaarrfk force-pushed the prefer_cached_host_memory_for_readback branch from 3c328ce to 59571ec Compare August 20, 2026 02:12
@hmaarrfk hmaarrfk added the automerge Merge the PR when CI passes label Aug 20, 2026
@conda-forge-admin
conda-forge-admin merged commit 4009c43 into conda-forge:main Aug 20, 2026
9 checks passed
@conda-forge-admin

Copy link
Copy Markdown
Contributor

Hi! This is the friendly conda-forge automerge bot!

I considered the following status checks when analyzing this PR:

  • linter: passed
  • azure: passed
  • github-actions: passed

Thus the PR was passing and merged! Have a great day!

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

Labels

automerge Merge the PR when CI passes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants