Skip to content

rocm: model weights in host RAM on integrated APUs (Strix Halo) - #1028

Closed
Piega wants to merge 1 commit into
antirez:mainfrom
Piega:strixhalo-host-ram-weights
Closed

Piega wants to merge 1 commit into
antirez:mainfrom
Piega:strixhalo-host-ram-weights

Conversation

@Piega

@Piega Piega commented Sep 12, 2026

Copy link
Copy Markdown

Fixes OOM loading resident DeepSeek V4 Flash Q2 (80.76 GiB) on Strix Halo systems, and unlocks the other 128 GB UMA resident models on ROCm.

Problem

The ROCm model arena allocates weights with hipMalloc, which on integrated APUs is bound by the small device memory pool exposed to the GPU (~62 GiB, set by the BIOS UMA frame buffer). A resident Flash Q2 (80.76 GiB) therefore failed during tensor-span preparation:

ds4: model arena alloc failed for tensor-span:108 (528.00 MiB request): out of memory

Fix

On integrated APUs, allocate model arena chunks via hipHostMalloc (falling back to hipMallocManaged), mirroring how llama.cpp's GGML_HIP_UMA keeps weights in host RAM while they stay GPU-visible over the UMA fabric. Discrete GPUs keep the existing hipMalloc path untouched; DS4_ROCM_FORCE_DEVICE_MEM=1 restores the previous behavior.

Scope

The documented alternative for the small-pool problem is raising the GPU-visible pool via kernel boot parameters (amdgpu.gttsize=126976 ttm.pages_limit=32505856 ttm.page_pool_size=32505856, see docs/STRIX_HALO.md), which gives ~124 GiB GTT. Hosts that already apply those parameters do not need this change.

This patch is for the stock case: some integrated systems expose only ~62 GiB to the GPU with default firmware/kernel settings and cannot (or do not want to) change boot parameters or reboot. There, routing the resident weight arena to host memory makes 80-91 GiB resident models load without any host configuration change. Verified on a Bosgame M5 (Ryzen AI Max+ 395, Radeon 8060S, 128 GB) running stock boot parameters.

Verified

Bosgame M5 (Ryzen AI Max+ 395, Radeon 8060S, 128 GB, ROCm 10.0, this branch).

DeepSeek V4 Flash models, resident:

model prefill (new interval) steady gen peak resident
Flash Q2 273-284 tok/s (ctx 4-8k) 13.0-13.7 tok/s 80.76 GiB
Flash Q2 + DSpark drafter 206-286 tok/s 22.8-24.3 tok/s 80.76 GiB + 5.6 GiB
Flash Q2-Q4 (L37-42 Q4K) 103-151 tok/s 13.1-13.6 tok/s 90.88 GiB

All load in ~30 s; KV is 0.41-0.46 GiB. GLM 5.3 Flash Q2 also runs resident (90 GiB) with DS4_GLM_MEMORY_GUARD=0 (the guard budgets from the ~61 GiB device pool); vision mode (V4 Flash Vision-Exp + encoder) works on ROCm.

Note: this approach is complementary to #361 (opt-in DS4_CUDA_MANAGED for high-context OOM on large-carveout UMA APUs): #361 addresses long-context scratch by defaulting weight/scratch placement policy on demand, while the change here makes resident weights work on integrated APUs out of the box by routing the weight arena to host memory.

@Piega
Piega force-pushed the strixhalo-host-ram-weights branch 2 times, most recently from 663462c to 8b46251 Compare September 12, 2026 21:23
Strix Halo (gfx1151) exposes a small device memory pool (~62 GiB set by the
BIOS UMA frame buffer), so a resident DeepSeek V4 Flash Q2 (80.76 GiB)
failed with OOM while preparing model tensor spans. On integrated APUs the
model arena now allocates via hipHostMalloc (fallback hipMallocManaged),
mirroring llama.cpp GGML_HIP_UMA: weights live in host RAM and stay GPU
visible over the UMA fabric, bypassing the device pool ceiling. Discrete
GPUs are unchanged; DS4_ROCM_FORCE_DEVICE_MEM restores previous behavior.

Verified on Bosgame M5 (Ryzen AI Max+ 395, Radeon 8060S, 128 GB, ROCm 10):
80.76 GiB resident in ~30 s, prefill ~273-284 tok/s (ctx 4-8k), steady
generation ~13 tok/s.
@Piega

Piega commented Sep 14, 2026

Copy link
Copy Markdown
Author

Follow-up with measured evidence for the scope question, from a machine that ran both configurations.

On a Bosgame M5 (Ryzen AI Max+ 395, 128 GB) I measured the same resident model (DeepSeek-V4-Flash-IQ2XXS ... 0731, 80.76 GiB) in two host configurations:

host configuration unmodified main this PR
stock firmware/kernel (GPU-visible pool ~61 GiB) OOM: model arena alloc failed for tensor-span … out of memory loads, prefill 273-284 t/s, gen 13.2-13.7 t/s
BIOS UMA 512 MB + amdgpu.gttsize=126976 ttm.pages_limit=32505856 (GTT 124 GiB) loads fine, prefill 287-297 t/s, gen 14.0-14.8 t/s (not needed)

So the patch is exactly a no-reconfiguration fallback: where the documented kernel parameters are applied it is unnecessary and marginally slower (weights in GTT rather than pinned host memory); where the host runs stock firmware defaults it is the difference between OOM and a working resident model. Worth keeping that distinction in the description if reviewers want the smaller surface — the alternative would be documentation only ("set these kernel parameters"), which is what upstream already recommends.

One extra data point on the same box: the ~62 GiB pool also silently reduced a streaming configuration's expert cache (89 GB requested → 51 GiB admitted), which went back to 81.9 GiB after the kernel parameters were applied. Same root cause, different symptom.

@Piega

Piega commented Sep 16, 2026

Copy link
Copy Markdown
Author

Update from the reporting machine: the box now runs the boot parameters documented for Strix Halo (amdgpu.gttsize=126976 ttm.pages_limit=32505856). With those in place a clean build of this branch without the patch ran DeepSeek-V4.1-Flash-Q2 SSD-streaming end to end (planned 70.66 GiB fits inside the expanded GTT pool; benchmark numbers unchanged vs the patched build: prefill ~49.5 tok/s, gen ~10.1 tok/s at 2048 ctx).

So on hosts with the documented GTT/TTM settings this patch is no longer needed — it would only remain relevant for stock-kernel systems with the small BIOS-UMA device pool. Happy to close or keep as an optional fallback, maintainer call.

@Piega Piega closed this Sep 16, 2026
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.

1 participant