Skip to content

Commit 513ebfc

Browse files
committed
fix(core): compare CUdeviceptr as int so the VMM grow fast path can run
`modify_allocation()` asks `cuMemAddressReserve` for the address immediately after the current range, then checks whether the driver granted that exact address before taking the fast path. `cuMemAddressReserve` returns `new_ptr` as a `CUdeviceptr`. That type defines `__int__` and `__repr__` but no `__eq__` or `__richcmp__`, so `new_ptr != <int>` falls back to identity comparison and is unconditionally true. The guard is therefore always taken and `_grow_allocation_fast_path` is unreachable: every grow runs the slow path, re-reserving the whole range and remapping it, so the buffer's base pointer changes even when a contiguous extension was available. Convert with `int()` before comparing. Reported as defect 2 in #2388. Two tests cover this: - `test_cudeviceptr_is_never_equal_to_plain_int` pins the underlying pitfall, that `CUdeviceptr(x) == x` is False and call sites must go through `int()`. - `test_vmm_allocator_grow_dispatches_to_fast_path` stubs `cuMemAddressReserve` to grant the requested address and asserts the dispatch reaches the fast path. It fails on the current code, which records "slow". Note this makes a previously unreachable code path live, so it is a behavior change rather than a pure cleanup: successful contiguous grows now preserve the base pointer instead of moving it. The existing `test_vmm_allocator_grow_allocation_fast_path` already exercised `_grow_allocation_fast_path` directly, so the helper itself is covered; what was missing was coverage of the dispatch decision that reaches it. Signed-off-by: Aryan Putta <aryansputta@gmail.com>
1 parent 76bac4e commit 513ebfc

2 files changed

Lines changed: 64 additions & 1 deletion

File tree

cuda_core/cuda/core/_memory/_virtual_memory_resource.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,11 @@ def modify_allocation(
265265
0,
266266
)
267267

268-
if res != driver.CUresult.CUDA_SUCCESS or new_ptr != (int(buf.handle) + aligned_prev_size):
268+
# `new_ptr` is a `CUdeviceptr`, which defines `__int__` but not `__eq__`, so
269+
# comparing it directly against a plain int always evaluates False. Without
270+
# the `int()` conversion this branch is always taken and the fast path below
271+
# is unreachable, even when the driver granted the requested address.
272+
if res != driver.CUresult.CUDA_SUCCESS or int(new_ptr) != (int(buf.handle) + aligned_prev_size):
269273
# Check for specific errors that are not recoverable with the slow path
270274
if res in (
271275
driver.CUresult.CUDA_ERROR_INVALID_VALUE,

cuda_core/tests/test_memory.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,65 @@ def __init__(self, size):
10351035
assert ("set_access", new_ptr, aligned_additional, 1) in calls
10361036

10371037

1038+
@pytest.mark.agent_authored(model="claude-opus-4-8")
1039+
def test_cudeviceptr_is_never_equal_to_plain_int():
1040+
"""`CUdeviceptr` has `__int__` but no `__eq__`, so `==` against an int is always False.
1041+
1042+
Address comparisons against driver return values must go through `int()`.
1043+
"""
1044+
ptr = driver.CUdeviceptr(0x1000)
1045+
assert int(ptr) == 0x1000
1046+
assert ptr != 0x1000
1047+
1048+
1049+
@pytest.mark.agent_authored(model="claude-opus-4-8")
1050+
def test_vmm_allocator_grow_dispatches_to_fast_path(init_cuda, monkeypatch):
1051+
"""A contiguous reservation must dispatch to the fast path, not the slow path.
1052+
1053+
`cuMemAddressReserve` returns a `CUdeviceptr`. Comparing that object against
1054+
the plain-int address that was requested is always False, so the dispatch in
1055+
`modify_allocation` fell through to the slow path (full re-reserve and remap,
1056+
base pointer changes) even when the driver granted exactly the adjacent range.
1057+
"""
1058+
device = Device()
1059+
if not device.properties.virtual_memory_management_supported:
1060+
pytest.skip("Virtual memory management is not supported on this device")
1061+
1062+
vmm_mr = VirtualMemoryResource(
1063+
device,
1064+
config=VirtualMemoryResourceOptions(handle_type="win32_kmt" if IS_WINDOWS else "posix_fd"),
1065+
)
1066+
try:
1067+
buffer = vmm_mr.allocate(2 * 1024 * 1024)
1068+
except NotImplementedError:
1069+
pytest.skip("handle_type not implemented on this platform")
1070+
1071+
# Grant the reservation at exactly the address the caller asked for, which is
1072+
# the contiguous-extension case the fast path exists to serve.
1073+
def fake_addr_reserve(size, alignment, addr, flags):
1074+
return (driver.CUresult.CUDA_SUCCESS, driver.CUdeviceptr(addr))
1075+
1076+
chosen = []
1077+
1078+
def record_fast(*_args, **_kwargs):
1079+
chosen.append("fast")
1080+
return buffer
1081+
1082+
def record_slow(*_args, **_kwargs):
1083+
chosen.append("slow")
1084+
return buffer
1085+
1086+
monkeypatch.setattr(driver, "cuMemAddressReserve", fake_addr_reserve)
1087+
monkeypatch.setattr(vmm_mr, "_grow_allocation_fast_path", record_fast)
1088+
monkeypatch.setattr(vmm_mr, "_grow_allocation_slow_path", record_slow)
1089+
1090+
try:
1091+
vmm_mr.modify_allocation(buffer, 4 * 1024 * 1024)
1092+
assert chosen == ["fast"]
1093+
finally:
1094+
buffer.close()
1095+
1096+
10381097
def test_vmm_allocator_rdma_unsupported_exception():
10391098
"""Test that VirtualMemoryResource throws an exception when RDMA is requested but device doesn't support it.
10401099

0 commit comments

Comments
 (0)