Skip to content

ggml-cuda: use cudaMemcpyDefault in the ggml_cuda_cpy 2D fast path - #157

Open
danielhanchen wants to merge 1 commit into
masterfrom
fix/cpy-memcpy-default
Open

ggml-cuda: use cudaMemcpyDefault in the ggml_cuda_cpy 2D fast path#157
danielhanchen wants to merge 1 commit into
masterfrom
fix/cpy-memcpy-default

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Overview

One word, plus the vendor mapping that makes it compile. Replaces #155, which showed 278 files because its branch was cut from the upstream b10687 tag while targeting fork master; the change itself was always these three files.

ggml/src/ggml-cuda/cpy.cu            +8/-1
ggml/src/ggml-cuda/vendors/hip.h     +1/-0
ggml/src/ggml-cuda/vendors/musa.h    +1/-0

The defect

The 2D fast path added by ggml-org#25057 copies with cudaMemcpyDeviceToDevice. That argument is not a hint, it is an assertion that both pointers are device resident, and it lets the runtime skip residency resolution.

Under GGML_CUDA_ENABLE_UNIFIED_MEMORY the allocator returns hipMallocManaged pages. Those migrate to the host once the working set outgrows VRAM, so past a footprint threshold the assertion is false and the copy reads the wrong memory. cudaMemcpyDefault resolves residency per pointer, and is a no-op when both pointers really are on the device.

Neither vendors/hip.h nor vendors/musa.h mapped cudaMemcpyDefault. The one copy kind that resolves residency was unreachable from this file on non-CUDA backends, which is plausibly why the defect was easy to write: on HIP the only kinds spelled cuda* were the explicit ones, so the fast path used an explicit kind because that is what compiled. The first build of this change failed with use of undeclared identifier 'cudaMemcpyDefault'.

How it was found

A release bisect over prebuilt ROCm tarballs put the corruption on one commit: 0ed235ea, b9826 clean and b9827 broken, direct parent and child, with 13 consecutive clean builds below and 5 broken above.

A revert-only build then proved causation. On gfx1151, in one job on one host, with a 45.1 GiB model at 73% of RAM: the reverted build produced identical tokens with the variable unset and set, while the stock build reproduced the reported fingerprint ' Paris.,,, or or or is is is is,,,,, from from from'.

Why this and not the revert

Deleting the fast path drops same-type strided copies of types outside F32/F16/BF16/I32 onto GGML_ABORT("unsupported type combination") at cpy.cu:609. That is coverage ggml-org#25057 added for the GDN recurrent snapshot with -np 4. Changing the copy kind keeps it.

Verification

Run on gfx1151, both cells in one job on one host, same model, same flags:

cell binary UMA unset UMA=1 verdict
D1 this change Paris. The capital of Germany is Berlin... 47.7 tok/s identical 30 tokens, 40.7 tok/s NO_REGRESSION
D2 stock b10687-mix-67dfc8b same clean text, 48.2 tok/s Paris.,,, or or or is is is is,,,,, 45.0 tok/s REGRESSION

D2 is the load-bearing half: a build that failed to load, or a host too starved to reproduce, would also have made D1 look clean.

Trust checks on all four states: server_ready true, no crash, no SIGABRT, loads 6.0 / 43.6 / 18.0 / 35.1 s against a 900 s timeout. Binaries confirmed per file rather than by cell name. D1 and D2 base token vectors are identical, so the change does not perturb the path that was already correct.

What is not covered

One model, one quant, one configuration, one host. No discrete GPU and no CUDA measurement, and this call site is shared with the path that was never broken. The comparable throughput pair is the two base states, 47.7 against 48.2, which is evidence against a large penalty rather than proof of none: cudaMemcpyDefault does a pointer attribute lookup per call, and a same-output benchmark is what would settle it.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 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-31T08:17:56.527627Z 6c6da89 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 added a commit that referenced this pull request Aug 31, 2026
ROCm APU user with no opt-in. #157 stops the unified-memory corruption for users
who have GGML_CUDA_ENABLE_UNIFIED_MEMORY set.

both would apply the same hunks twice and fail the resolve, so only one can be
listed. Both entries come out once a base tag carries the upstream merge.

Co-authored-by: danielhanchen <elliegouldingstuff@gmail.com>
The 2D fast path added in ggml-org#25057 copies with cudaMemcpyDeviceToDevice.
That argument is not a hint, it is an assertion that both pointers are device
resident. Under GGML_CUDA_ENABLE_UNIFIED_MEMORY the allocator returns
hipMallocManaged pages, which migrate to the host once the working set exceeds
VRAM, so at high footprint the assertion is false and the copy reads the wrong
memory.

cudaMemcpyDefault resolves residency per pointer instead, and is a no-op when
both pointers really are on the device.

Neither vendors/hip.h nor vendors/musa.h mapped cudaMemcpyDefault, so the one
copy kind that resolves residency was unreachable from this file on non-CUDA
backends. Both shims now carry the mapping.

Measured on gfx1151, 45.1 GiB model at 73% of RAM, in one job on one host:
this build produced identical tokens with the variable unset and set, while the
stock build in the same job reproduced the reported corruption. A revert of
25057 is also clean but drops same-type strided copies outside F32/F16/BF16/I32
onto GGML_ABORT at cpy.cu:609, losing the coverage 25057 added for the GDN
recurrent snapshot with -np 4. This keeps it.

Not measured against a discrete GPU or the CUDA path.
@danielhanchen
danielhanchen force-pushed the fix/cpy-memcpy-default branch from 453cbcb to 6c6da89 Compare August 31, 2026 08:13
danielhanchen added a commit that referenced this pull request Aug 31, 2026
…161)

* unsloth: repin ggml-org#25731 to the commit that merges onto b10705

edee0e1 stopped applying to the current base tag, which failed the pin
preflight. Because the preflight stops at the first conflict, it also meant the
two AMD fixes pinned by #160 were never dry-run merged at all.

44eb88e is the head after the upstream conflicts were resolved; the PR is
MERGEABLE upstream again as of 2026-08-31T08:06Z.

* unsloth: repoint the AMD pins at commits based on an upstream ancestor

#157 and #158 were branched from fork master, which is right for a small PR
diff and wrong for a pin. Fork master has diverged from upstream (it deletes a
dozen upstream workflow files), so merging those commits onto the base tag
dragged the whole divergence in and conflicted modify/delete on twelve
.github/workflows files. That is what exited the preflight with no message
after 'ok #137'.

The pins that work are branched from an upstream commit that is an ancestor of
both master and the base tag, so they carry only their own delta. Both branches
are now rebased onto 11cd988 on that pattern, and verified locally to merge
onto b10705 for a net +35/-3 across 4 files, which is the two fixes and nothing
else.

---------

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

@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: 6c6da89266

ℹ️ 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/cpy.cu
Comment on lines +478 to +479
// GGML_CUDA_ENABLE_UNIFIED_MEMORY these buffers come from
// hipMallocManaged, and managed pages are not guaranteed device

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the shared-path comment backend-neutral and concise

In CUDA and MUSA builds, these buffers come from cudaMallocManaged and musaMallocManaged, respectively, so the backend-shared comment incorrectly states that they come from hipMallocManaged. Generalize the explanation to managed allocations and reduce the seven-line hard-wrapped comment to the repository's expected one or two concise lines.

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

Useful? React with 👍 / 👎.

@danielhanchen danielhanchen added the bug Something isn't working label Aug 31, 2026
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