Skip to content

ggml-cuda: make GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 actually disable it, and say so on HIP - #149

Open
danielhanchen wants to merge 1 commit into
masterfrom
uma/env-bool-and-warn
Open

ggml-cuda: make GGML_CUDA_ENABLE_UNIFIED_MEMORY=0 actually disable it, and say so on HIP#149
danielhanchen wants to merge 1 commit into
masterfrom
uma/env-bool-and-warn

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Overview

Two small changes to ggml-cuda.cu, both aimed at the same problem: users on AMD APUs are running with unified memory on, often without knowing, and cannot turn it off by the obvious means.

1. =0 enabled it

Both read sites test presence:

if (getenv("GGML_CUDA_ENABLE_UNIFIED_MEMORY") != nullptr) {   // line 142
bool uma_env = getenv("GGML_CUDA_ENABLE_UNIFIED_MEMORY") != nullptr;  // line 4792

The name is spelled as a positive, so =0 is the first thing anyone reaches for, and it did the exact opposite of what they asked with no indication. Presence testing is the right call for a name like GGML_CUDA_NO_PINNED, where setting it is the only sensible use. It is the wrong call here. GGML_CUDA_DISABLE_FUSION in this same file already parses its value for precisely this reason.

Now: empty and the usual falsy spellings are off, anything else is on. =1, =true, =on and =yes behave exactly as before, so the only behaviour change is for values that were always meant to mean no.

2. Warn once on HIP

Every report I have read of managed allocation misbehaving on an APU came from someone who did not know a front-end had set the variable on their behalf. A single line naming the variable and pointing at ggml-org#26148 is most of the diagnosis, and it costs one GGML_LOG_WARN_ONCE. HIP only, since that is where the reports are.

Scope

This is not a fix for the corruption in ggml-org#26148. It is the thing that has to be true before anyone can test around it: a switch that responds to being switched off, and a build that tells you the switch is on.

Verification

The helper is compile-checked standalone under -Wall -Wextra and exercised against unset, 1, 0, empty, true, False, OFF, on, yes, no, 2 and a junk value, which behave as described above.

I cannot build CUDA or HIP where I am, so the prebuilt legs are the first real check on the change in context. Worth a look at whether the warning is too chatty for anyone deliberately running managed memory to fit a large model in a shared pool; I kept it to one line for the process, but I would not argue if a reviewer wants it gated further.

@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 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 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>
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