Skip to content

HIP: say once that GGML_CUDA_ENABLE_UNIFIED_MEMORY is on - #149

Open
danielhanchen wants to merge 3 commits into
base/upstream-fcac19079from
uma/env-bool-and-warn
Open

danielhanchen wants to merge 3 commits into
base/upstream-fcac19079from
uma/env-bool-and-warn

Conversation

@danielhanchen

@danielhanchen danielhanchen commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

Overview

One small change to ggml-cuda.cu: on HIP, say once that GGML_CUDA_ENABLE_UNIFIED_MEMORY is on. Users on AMD APUs often run with unified memory without knowing it, because a front-end set the variable for them.

The other half of the original change, making GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 turn it off, is upstream since ggml-org#30327 (ggml_cuda_env_flag, which parses the value with atoi, so 1 enables it and 0, empty or a word such as true do not). This branch now carries only the warning on top of it.

The warning

After a successful hipMallocManaged, once per process:

GGML_CUDA_ENABLE_UNIFIED_MEMORY is set, allocating device memory as managed. On integrated GPUs this draws host RAM instead of the device carve-out, which is usually slower and can reduce the largest model that will load. Unset the variable or set it to 0 to disable it.

It is printed only when the managed allocation succeeds. When hipMallocManaged returns hipErrorNotSupported (for example on Windows), the existing fallback to hipMalloc and its own warning are unchanged, so the two messages no longer contradict each other. HIP only, since that is where the reports come from. It does not point at the old corruption report (ggml-org#26148): that defect is in the 2D copy fast path on managed pages and is fixed separately.

Verification

HIP is not built on this host. The change moves an existing GGML_LOG_WARN_ONCE call into the existing err == hipSuccess branch; CUDA and non-HIP builds are unaffected (the code is inside #if defined(GGML_USE_HIP)).

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-08-31T09:28:23.033655Z b65a2dc New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@danielhanchen

Copy link
Copy Markdown
Member Author

One note on how this reaches users, since I got it wrong earlier today on #145.

The nightly tree is the upstream tag plus scripts/unsloth/pr-set.json, not fork master, so merging this alone changes nothing in a shipped binary. If it is wanted in the nightlies it needs a pin entry pointing at this branch's commit, kept until the change lands upstream. I have deliberately not added one in this PR: the pin set should not gain an entry for code nobody has reviewed yet, and this is a behaviour change to an env var rather than a straight bug fix.

Happy to open the pin as a follow-up, or to take it upstream first if that is preferred, in which case the pin points at the ggml-org PR and retires itself.

ggml tests getenv(...) != nullptr, so =0 enables managed allocation. The name is
spelled as a positive, so people reasonably write =0 to turn it off and get the
opposite. GGML_CUDA_DISABLE_FUSION in this file already parses its value for the
same reason. Empty and the usual falsy spellings are off; =1, =true, =on and =yes
are unchanged.

This is no longer a correctness bug. Before the cpy 2D fast path was fixed, =0
left the user corrupted while they believed they had opted out. It now costs
throughput and capacity instead: on an integrated GPU managed allocation draws
host RAM instead of the device carve-out rather than adding to it, measured at
about 15% slower, and a model that loads without the variable can be OOM-killed
with it.

The HIP warning is rewritten accordingly. The earlier draft warned about
corrupted output and linked ggml-org#26148; shipping that alongside the fast path
fix would tell users to chase a defect their build does not have. It now states
the cost, which is what remains true.

Note this changes behaviour for every CUDA and HIP user who currently sets =0,
not only AMD: they lose managed allocation, which is the point, but it is not a
no-op.

Rebased onto an upstream ancestor of both master and the base tag so it can be
pinned; a branch cut from fork master drags master's divergence into the pin
merge and conflicts on the deleted upstream workflow files.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b65a2dce12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ggml/src/ggml-cuda/ggml-cuda.cu Outdated
Comment on lines +180 to +183
GGML_LOG_WARN_ONCE("GGML_CUDA_ENABLE_UNIFIED_MEMORY is set, allocating device memory as managed. "
"On integrated GPUs this draws host RAM instead of the device carve-out, which is "
"usually slower and can reduce the largest model that will load. Unset the variable "
"to disable it.\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Emit the managed-memory warning only after success

On HIP configurations where cudaMallocManaged returns hipErrorNotSupported, such as the Windows case handled by the fallback below, this warning claims that memory is being allocated as managed and describes managed-memory costs before the allocation is attempted; the code then uses ordinary cudaMalloc instead. Emit this warning only from the err == hipSuccess branch so users do not receive an inapplicable warning immediately followed by the fallback warning.

Useful? React with 👍 / 👎.

Comment thread ggml/src/ggml-cuda/ggml-cuda.cu Outdated
Comment on lines +101 to +105
// Most ggml switches test presence only, and for a name like GGML_CUDA_NO_PINNED
// that is right: the only sensible use is to set it. GGML_CUDA_ENABLE_UNIFIED_MEMORY
// is spelled as a positive, so people reasonably write =0 to turn it off, and under a
// presence test that enabled the very path they were trying to leave. GGML_CUDA_DISABLE_FUSION
// in this file already parses its value for the same reason.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Condense the hard-wrapped comment narratives

Replace this implementation-history narrative and the similar long block before the managed allocation with concise comments that retain only non-obvious invariants. These blocks hard-wrap sentences and document prior drafts, issue history, and obvious environment-variable behavior across many lines, contrary to this repository's explicit requirement that comments usually remain 1-2 lines, avoid excessive commentary, and not be hard-wrapped.

AGENTS.md reference: AGENTS.md:L74-L78

Useful? React with 👍 / 👎.

danielhanchen added a commit that referenced this pull request Aug 31, 2026
…les it (#162)

ggml tests getenv(...) != nullptr, so =0 enables managed allocation. With #157
pinned this is no longer a correctness bug, but it still costs about 15%
throughput and can lower the ceiling: managed draws host RAM instead of the
device carve-out rather than adding to it, so a model that loads without the
variable can be OOM-killed with it.

Verified locally to co-merge onto b10705 with #157 and #158, net +79/-5 across
4 files.

Co-authored-by: danielhanchen <elliegouldingstuff@gmail.com>
@danielhanchen

Copy link
Copy Markdown
Member Author

=0 enabling it is observable on gfx1151, and this fork's prebuilt already behaves correctly

Measured on a Ryzen AI Max+ PRO 395 / Radeon 8060S (gfx1151), 128 GB, Windows 11, with the graphics carve-out at 96 GiB — so Windows sees only 31.78 GiB of host RAM. That configuration makes the bug loud: managed pages come from visible host RAM rather than the carve-out, so a model that fits the carve-out comfortably cannot fit host RAM, and the machine starves instead of merely slowing down.

Model: Qwen3-Next-80B-A3B-Instruct UD-Q4_K_XL, 42.90 GiB, -ngl 999. Run under a watchdog that kills the process if free RAM crosses a floor.

build env outcome
ggml-org b10766 win-rocm-7.14 GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 host starved to 5.21 GiB free, killed
unsloth b10798-mix-659e406 GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 completed normally, pp128 158.71 t/s
unsloth b10798-mix-659e406 GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 free RAM to 0.01 GiB, killed
unsloth b10798-mix-659e406 unset completed normally

So on mainline, =0 behaves like =1 — the presence test this PR describes. On this fork's current prebuilt, =0 behaves like unset, which is what a user typing =0 is asking for.

The =1 row is worth keeping in mind for the warning half of this PR: at a large carve-out the variable is not a performance trade, it is a hard denial of service on the host. A user who set it once for a big model on a small carve-out, then raised their carve-out, would hit this with no indication of why. That is precisely the population the GGML_LOG_WARN_ONCE is aimed at, and it argues for keeping the warning rather than gating it further.

Caveats

  • One host, one driver, one model. Windows only.
  • The mainline package needed its ROCm 7.14.0 runtime staged beside it to use the GPU at all (rocblas, hipblas, libhipblaslt, amdhip64_7 and the kernel directories); without it, --list-devices reports (none) and it silently falls back to CPU. Backend was verified as ROCm : NO_VMM = 1 in system_info for every GPU cell.
  • This measures only the switch behaviour. It says nothing about the underlying corruption in ggml-org#26148, which this PR is explicit about not fixing.

…_enabled()

b11609 parses GGML_CUDA_ENABLE_UNIFIED_MEMORY by value (ggml-org#30327), so =0
already disables it upstream. Drop ggml_cuda_env_enabled() and keep only the
once-per-process HIP warning.
On hipErrorNotSupported the allocation falls back to hipMalloc, so the
warning printed before it described memory that was never managed. Also
name =0 as the way to turn it off.
@danielhanchen danielhanchen changed the title ggml-cuda: make GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 actually disable it, and say so on HIP HIP: say once that GGML_CUDA_ENABLE_UNIFIED_MEMORY is on Oct 14, 2026
danielhanchen added a commit that referenced this pull request Oct 15, 2026
Pin #264, #266; repin #243, #251, #149, #240: MoE prompt processing, mmap populate, glm5-next onto b11617

This branch has not been deployed

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant