Repository navigation
Conversation
A DeviceMemoryResource sent through multiprocessing, and a pickled VirtualMemoryResource, named their device by ordinal, and the VirtualMemoryResource also sent its peers as ordinals. Ordinals are per process, so a receiver with a different CUDA_VISIBLE_DEVICES rebuilt the resource on the wrong GPU or granted peer access to the wrong GPU. Send the owner and the peers by UUID and map them back in the receiver with a new private helper. Raise a clear RuntimeError when no visible device has the UUID. The tests reverse the device order in the child through CUDA_VISIBLE_DEVICES and check the imported buffer's device UUID. Closes NVIDIA#3097 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The check-cython-not-none hook from main requires it on a def parameter annotated with a cdef class. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ce-uuid Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A generator in `peers` was consumed by the first allocation. Later allocations granted no peer access, and a pickled resource sent no peer UUIDs, so the receiver mapped the memory without peer access. `__post_init__` now converts `peers` to a tuple, which also covers options given as a dict, through `replace()`, or per call to `modify_allocation()`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Device.__reduce__ sent the ordinal, so a process with a different CUDA_VISIBLE_DEVICES unpickled a different GPU. It now sends the UUID, and the receiver maps it back with _device_from_uuid(), which raises RuntimeError when the device is not visible. Closes NVIDIA#3196. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uuid Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
📝 Summary
Priority: ➖ Normal Change: Bug fix · Severity of issue fixed: Medium Merge Risk: 🔵 Low · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Source mode: Auto
- Repository: NVIDIA/cuda-python
- Branch: main
- File: .coderabbit.yaml
- Commit: afa6249
- Layers: Repository YAML
- Review profile: CHILL
- Plan: Enterprise
- Run ID:
6c0f850a-0fcc-4f2e-abda-c0c16ee5a016
📒 Files selected for processing: 10
cuda_core/cuda/core/_device.pyicuda_core/cuda/core/_device.pyxcuda_core/cuda/core/_memory/_device_memory_resource.pyicuda_core/cuda/core/_memory/_device_memory_resource.pyxcuda_core/cuda/core/_memory/_virtual_memory_resource.pyicuda_core/cuda/core/_memory/_virtual_memory_resource.pyxcuda_core/docs/source/release/1.3.0-notes.rstcuda_core/tests/memory_ipc/test_device_uuid.pycuda_core/tests/test_device.pycuda_core/tests/test_memory.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.
| def test_device_memory_resource_buffer(ipc_mempool_device_x2): | ||
| """A pool-backed buffer comes back on the device that owns it, not on the device with the same ordinal.""" | ||
| dev0, dev1 = ipc_mempool_device_x2 | ||
| mr = DeviceMemoryResource(dev0, options=DeviceMemoryResourceOptions(max_size=POOL_SIZE, ipc_enabled=True)) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n 140,165p cuda_core/tests/memory_ipc/test_device_uuid.py
sed -n 1,60p cuda_core/tests/memory_ipc/conftest.pyRepository: NVIDIA/cuda-python
Length of output: 2879
Close the owned pool and buffer in finally.
test_device_memory_resource_buffer closes buf and mr only after _send_to_child and _check_report return. If either call raises, the owned pool can stay open. The next init_cuda test can then fail with UnreleasedMemoryResourceWarning, which pytest.ini escalates to an error. Release the buffer and pool on every path. Initialize buf before the protected region so a failed allocation does not raise NameError in the cleanup block.
🐛 Suggested fix
--- "a/cuda_core/tests/memory_ipc/test_device_uuid.py"
+++ "b/cuda_core/tests/memory_ipc/test_device_uuid.py"
@@ -148,16 +148,19 @@
def test_device_memory_resource_buffer(ipc_mempool_device_x2):
"""A pool-backed buffer comes back on the device that owns it, not on the device with the same ordinal."""
dev0, dev1 = ipc_mempool_device_x2
mr = DeviceMemoryResource(dev0, options=DeviceMemoryResourceOptions(max_size=POOL_SIZE, ipc_enabled=True))
- buf = mr.allocate(NBYTES, stream=dev0.default_stream)
- _fill(dev0, buf)
-
- report = _send_to_child(buf, visible=(dev1, dev0))
- _check_report(report, dev0)
-
- buf.close()
- dev0.sync()
- mr.close()
+ buf = None
+ try:
+ buf = mr.allocate(NBYTES, stream=dev0.default_stream)
+ _fill(dev0, buf)
+
+ report = _send_to_child(buf, visible=(dev1, dev0))
+ _check_report(report, dev0)
+ finally:
+ if buf is not None:
+ buf.close()
+ dev0.sync()
+ mr.close()
@pytest.mark.agent_authored(model="claude-opus-5-5")
|
Summary
A pickled
Devicenamed its device by ordinal, so a process with a differentCUDA_VISIBLE_DEVICESunpickled it as a different GPU.Device.__reduce__now sends the UUID, and the receiver maps it back with_device_from_uuid()from #3126. Unpickling raisesRuntimeError, naming the UUID and the visible devices, when the device is not visible.Changes
_device.pyx:Device.__reduce__returns(_device_from_uuid, (uuid,)). The class docstring describes the pickled form.Related Work
Closes #3196. Stacked on #3126, which adds
_device_from_uuid().🤖 Generated with Claude Code