Skip to content

UCT/CUDA_COPY/MD: Don't widen VMM range crossing a handle boundary - #12186

Merged
brminich merged 14 commits into
openucx:masterfrom
d4l3k:fix-vmm-whole-alloc-range
Oct 30, 2026
Merged

brminich merged 14 commits into
openucx:masterfrom
d4l3k:fix-vmm-whole-alloc-range

Conversation

@d4l3k

@d4l3k d4l3k commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What?

Don't widen a CUDA VMM registration to the containing physical allocation unless that allocation covers the whole requested range.

Fixes #12185.

Why?

cuMemGetAddressRange() returns only the cuMemCreate handle containing the address. The guard from #11461 compares lengths only, so a range shorter than a handle that starts inside one handle and ends in the next is widened to the first handle. The dmabuf is exported for that handle only, and ibv_reg_dmabuf_mr() fails with EINVAL. This hits PyTorch expandable_segments (20 MiB handles in one VA range) via NIXL.

This is needed for PyTorch: with the CUDA caching allocator in expandable_segments mode, tensors routinely span handle boundaries, so NIXL/UCX transfers of PyTorch tensors (e.g. torchstore weight sync, meta-pytorch/torchstore#249) fail to register. The only workaround today is UCX_CUDA_COPY_REG_WHOLE_ALLOC=off. NIXL wheels bundle UCX, so a v1.23.x backport would let PyTorch users pick this up.

How?

Compare the end of the containing allocation with the end of the requested range instead of comparing lengths. Also skip widening when cuMemGetAddressRange() reports a zero base address, as it does for host-located VMM, so the CUDA_COPY_REG_WHOLE_ALLOC=off workaround in the host_vmm_* tests is dropped.

Test plan:

cc @tvegas1 @nicolasnoble @tomerg-nvidia

d4l3k added 2 commits October 27, 2026 16:00
cuMemGetAddressRange() returns only the cuMem handle containing the address. The guard added for multi-handle VMM compared only lengths, so a range shorter than a handle that starts inside one handle and ends in the next was still widened to the first handle. The dmabuf was then exported for that handle only and ibv_reg_dmabuf_mr() failed with EINVAL. Keep the requested extent unless the handle contains the whole range.
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread test/gtest/uct/cuda/test_cuda_ipc_md.cc Outdated
@svc-nvidia-pr-review

Copy link
Copy Markdown

Residual coverage gap: both multi-handle VMM tests need a GPU with VMM support; they silently skip (skip_unless_ok) elsewhere, so CI without such a GPU gives no signal on this fix.

Related (out of scope for this PR): uct_cuda_ipc_mkey_pack() has a similar ucs_assertv(((uintptr_t)address + length) <= (key->d_bptr + key->b_len)) built on the same cuMemGetAddressRange() result (src/uct/cuda/cuda_ipc/cuda_ipc_md.c:343, 389-394). A spanning multi-handle VMM request could trip it.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c Outdated
@svc-nvidia-pr-review

Copy link
Copy Markdown

Both multi-handle VMM tests require a GPU with VMM support and silently skip via skip_unless_ok() otherwise, so CI without such a GPU gives no signal on this fix (already noted in a previous round).

If a driver returns the full reserved VA range from cuMemGetAddressRange() for a multi-handle mapping, the new test passes trivially even without the fix; it only asserts coverage, not that the fallback path was taken.

Duplicate detection against the PR conversation could not be performed with the tools available here; it was done only against the previously reported findings supplied in the prompt. Please re-run the inline/issue/review comment fetch before submitting.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c
Comment thread test/gtest/uct/cuda/test_cuda_ipc_md.cc Outdated
Comment thread test/gtest/uct/cuda/test_switch_cuda_device.cc
@svc-nvidia-pr-review

Copy link
Copy Markdown

Residual coverage gap: both multi-handle VMM tests and the host-VMM test need a GPU with VMM / host-NUMA VMM support and skip silently otherwise, so a CI machine without such a GPU gives no signal on this fix (already noted in earlier rounds).

Process note: only read_file / search_code / list_directory were available, so the PR's inline, issue, and review comment history could not be fetched. Duplicate detection was done only against the previously reported findings supplied in the prompt — please re-run the paginated comment fetch (pulls/12186/comments, issues/12186/comments, pulls/12186/reviews) before submitting, and convert any already-raised item into a +1 reaction instead of a new thread.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c Outdated
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c Outdated
@svc-nvidia-pr-review

Copy link
Copy Markdown

vmm_multi_handle_unaligned_range and host_vmm_mem_range need a GPU with VMM / host-NUMA VMM support and skip silently (skip_unless_ok) otherwise, so CI without such a GPU gives no signal on this fix (already raised in earlier rounds). Additionally, vmm_multi_handle_unaligned_range self-skips when the driver reports a range covering the request, so on such drivers it is a no-op — but that is the intended replacement for the earlier "passes trivially" concern, so it is addressed rather than new.

@d4l3k
d4l3k marked this pull request as ready for review October 28, 2026 00:06
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@d4l3k

d4l3k commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

Comment thread test/gtest/uct/cuda/test_switch_cuda_device.cc
@tvegas1

tvegas1 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Did you or your organization sign the CLA?

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Rename check_mem_query_range to check_mem_query_exact_range and also check the query is extended to the whole handle when the range is contained in it.
ADD_FAILURE() << "locality domain 1 allocation failed even though "
"domain 0 succeeded";
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The moved copy of vmm_locality_domain_mem_type is an older revision than the one it replaces (see test/gtest/uct/cuda/test_cuda_ipc_md.cc:790-805). The current version probes domain 1 first and skips when it's absent (since domain 1 is present only on devices with several locality domains), then only calls ADD_FAILURE() if domain 0 fails. This PR's version inverts the order: it skips only when domain 0 fails and calls ADD_FAILURE() when domain 1 fails. On a GPU with a single locality domain, domain 0 succeeds and domain 1 fails, so the moved test turns a legitimate skip into a hard test failure (gtest failure on any single-locality-domain GPU built with CU_MEM_LOCATION_TYPE_DEVICE_LOCALITY_DOMAIN available).

Suggested fix:

Suggested change
}
ucs_sys_device_t sys_dev0, sys_dev1;
/* Domain 1 is present only on a device with several locality domains, so
* its absence is what tells a single-domain device apart */
if (!check_domain(1, sys_dev1)) {
UCS_TEST_SKIP_R("single locality-domain device");
}
if (!check_domain(0, sys_dev0)) {
ADD_FAILURE() << "locality domain 0 allocation failed even though "
"domain 1 succeeded";
return;
}

Please move the current version of this test (test_cuda_ipc_md.cc:790) instead of the older one.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Resolve the conflict with openucx#12176 by keeping the moved test_cuda_copy_md tests in test_mem_alloc_device, and take its vmm_locality_domain_mem_type domain probe order.
Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c Outdated
Comment on lines +604 to +607
/* Host-located VMM reports a zero base address */
if (base_address == 0) {
goto out_ctx_pop;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

what about combining this condition and condition below?

Suggested change
/* Host-located VMM reports a zero base address */
if (base_address == 0) {
goto out_ctx_pop;
}
/* For multi-handle VMM, the physical allocation containing the address
* may not cover the whole requested range */
if ((base_address == 0) || /* host-located VMM reports a zero base */
(is_vmm && ((base_address + alloc_length) < (address + length)))) {
goto out_ctx_pop;
}

return true;
};

ucs_sys_device_t sys_dev0, sys_dev1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

pls rebase — master now probes domain 1 first, because domain 0 also succeeds on a single-locality-domain device and this ADD_FAILURE() then fires spuriously.

The vmm_locality_domain_mem_type test is moved here in its pre-rebase form: the base branch now contains a different version of this block (in test_cuda_ipc_md.cc) that probes domain 1 first, with the comment "Domain 1 is present only on a device with several locality domains, so its absence is what tells a single-domain device apart". The version being moved probes domain 0 first, so on a device that supports locality domains but has only one, domain 0 succeeds, domain 1 fails, and ADD_FAILURE() fires spuriously. Since this PR deletes that block from test_cuda_ipc_md.cc, a rebase will conflict there and the stale logic can silently land in the new location.

Suggested change
ucs_sys_device_t sys_dev0, sys_dev1;
ucs_sys_device_t sys_dev0, sys_dev1;
/* Domain 1 is present only on a device with several locality domains, so
* its absence is what tells a single-domain device apart */
if (!check_domain(1, sys_dev1)) {
UCS_TEST_SKIP_R("single locality-domain device");
}
if (!check_domain(0, sys_dev0)) {
ADD_FAILURE() << "locality domain 0 allocation failed even though "
"domain 1 succeeded";
return;
}

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/cuda/cuda_copy/cuda_copy_md.c Outdated
if (is_vmm && (alloc_length < length)) {
/* For multi-handle VMM, the physical allocation containing the address
* may not cover the whole requested range */
if (is_vmm && ((base_address + alloc_length) < (address + length))) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why keep is_vmm here? The new check is just "the reported range must cover the requested range", which also holds for legacy allocations.

@svc-nvidia-pr-review

Copy link
Copy Markdown

test/gtest/uct/cuda/test_switch_cuda_device.cc

vmm_multi_handle_range, vmm_multi_handle_unaligned_range and host_vmm_mem_range all depend on VMM / host-NUMA VMM support and silently skip via skip_unless_ok(), so a CI machine without such a GPU gives no signal on either fix (already raised in earlier rounds).

test/gtest/uct/cuda/test_switch_cuda_device.cc

vmm_multi_handle_unaligned_range asserts driver behavior (alloc_length == chunk_size, i.e. per-handle range), so it would fail on a driver that reports the whole VA reservation. This mirrors the "passes trivially" concern raised in an earlier round and appears to be the deliberate outcome of that discussion, so not re-opening it.

localized_mem_not_gdr_capable still carries CUDA_COPY_REG_WHOLE_ALLOC=off without an explanation; if that was the same zero/partial base-address problem, it could likely be dropped now. Not anchorable to a changed line.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

/* For multi-handle VMM, the physical allocation may be smaller than the
* mapped virtual range; preserve the caller's requested extent. */
if (is_vmm && (alloc_length < length)) {
/* For multi-handle VMM, the physical allocation containing the address

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

minor: the zero-base case is unrelated to multi-handle VMM (and not VMM-specific), pls split it out so each condition carries its own comment:

Suggested change
/* For multi-handle VMM, the physical allocation containing the address
if (base_address == 0) {
/* Host-located VMM reports a zero base address */
goto out_ctx_pop;
}
/* For multi-handle VMM, the physical allocation containing the address
* may not cover the whole requested range */
if (is_vmm && ((base_address + alloc_length) < (address + length))) {
goto out_ctx_pop;
}

@brminich
brminich enabled auto-merge (squash) October 28, 2026 10:40
@brminich

Copy link
Copy Markdown
Contributor

@d4l3k can you pls backport it to 1.23.x branch? This will enable this fix in NIXL 1.6

@brminich

Copy link
Copy Markdown
Contributor

@d4l3k can you pls confirm you have CLA signed?

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@d4l3k

d4l3k commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

@brminich I've signed the CLA

@d4l3k

d4l3k commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

@brminich backport is at #12188

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

@brminich
brminich merged commit 4cdc171 into openucx:master Oct 30, 2026
167 checks passed
brminich pushed a commit that referenced this pull request Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UCT/CUDA_COPY: dmabuf registration fails for VMM range crossing a handle boundary (expandable_segments)

5 participants