Skip to content

Commit 2197a4d

Browse files
Andy-Jostclaude
andcommitted
fix(cuda.core): say the Device pickle is for one machine; close test resources on every path
- The Device docstring and the release note say the pickled form is for processes on the same machine (asked on #3196). - The buffer tests in test_device_uuid.py release their buffers and pools in finally blocks, so a failed assertion cannot leave an owned pool open for the next test's leak check (CodeRabbit on #3198). - The module docstring cites #3196 for the Device requirement. Co-Authored-By: Claude Fable 5.1 <[email protected]>
1 parent 670b7d9 commit 2197a4d

4 files changed

Lines changed: 46 additions & 43 deletions

File tree

‎cuda_core/cuda/core/_device.pyi‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ class Device:
482482
A pickled :obj:`~_device.Device` names its device by UUID. Unpickling
483483
returns the device with that UUID in the receiving process, whatever its
484484
ordinal is there, and raises ``RuntimeError`` if that device is not
485-
visible.
485+
visible. The pickled form is for processes on the same machine.
486486
487487
Note
488488
----

‎cuda_core/cuda/core/_device.pyx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ class Device:
986986
A pickled :obj:`~_device.Device` names its device by UUID. Unpickling
987987
returns the device with that UUID in the receiving process, whatever its
988988
ordinal is there, and raises ``RuntimeError`` if that device is not
989-
visible.
989+
visible. The pickled form is for processes on the same machine.
990990

991991
Note
992992
----

‎cuda_core/docs/source/release/1.3.0-notes.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Fixes and enhancements
118118
named the device by ordinal, which names a different device when
119119
``CUDA_VISIBLE_DEVICES`` differs between the processes. Unpickling raises
120120
``RuntimeError`` when the device is not visible in the receiving process.
121+
The pickled form is for processes on the same machine.
121122
(`#3196 <https://github.com/NVIDIA/cuda-python/issues/3196>`__)
122123

123124
- Fixed a ``TypeError`` in :meth:`Program.compile` when retrying after PCH

‎cuda_core/tests/memory_ipc/test_device_uuid.py‎

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
66
The child process sees the parent's two devices in reversed order, so each
77
ordinal names the other device there. A ``Device`` must arrive as the device
8-
with the same UUID, the child must rebuild a resource for the device that
9-
owns the memory, and the peers of a ``VirtualMemoryResource`` must name the
10-
same devices as in the parent (issue #3097).
8+
with the same UUID (issue #3196), the child must rebuild a resource for the
9+
device that owns the memory, and the peers of a ``VirtualMemoryResource`` must
10+
name the same devices as in the parent (issue #3097).
1111
"""
1212

1313
import contextlib
@@ -149,15 +149,17 @@ def test_device_memory_resource_buffer(ipc_mempool_device_x2):
149149
"""A pool-backed buffer comes back on the device that owns it, not on the device with the same ordinal."""
150150
dev0, dev1 = ipc_mempool_device_x2
151151
mr = DeviceMemoryResource(dev0, options=DeviceMemoryResourceOptions(max_size=POOL_SIZE, ipc_enabled=True))
152-
buf = mr.allocate(NBYTES, stream=dev0.default_stream)
153-
_fill(dev0, buf)
154-
155-
report = _send_to_child(buf, visible=(dev1, dev0))
156-
_check_report(report, dev0)
157-
158-
buf.close()
159-
dev0.sync()
160-
mr.close()
152+
buf = None
153+
try:
154+
buf = mr.allocate(NBYTES, stream=dev0.default_stream)
155+
_fill(dev0, buf)
156+
report = _send_to_child(buf, visible=(dev1, dev0))
157+
_check_report(report, dev0)
158+
finally:
159+
if buf is not None:
160+
buf.close()
161+
dev0.sync()
162+
mr.close()
161163

162164

163165
@pytest.mark.agent_authored(model="claude-opus-5-5")
@@ -167,14 +169,14 @@ def test_virtual_memory_resource_buffer(vmm_ipc_device_x2):
167169
dev0, dev1 = vmm_ipc_device_x2
168170
mr = _vmm_resource(dev0)
169171
buf = mr.allocate(NBYTES)
170-
_fill(dev0, buf)
171-
172-
report = _send_to_child(buf, visible=(dev1, dev0))
173-
_check_report(report, dev0)
174-
assert report["peer_uuids"] == []
175-
176-
buf.close()
177-
dev0.sync()
172+
try:
173+
_fill(dev0, buf)
174+
report = _send_to_child(buf, visible=(dev1, dev0))
175+
_check_report(report, dev0)
176+
assert report["peer_uuids"] == []
177+
finally:
178+
buf.close()
179+
dev0.sync()
178180

179181

180182
@pytest.mark.agent_authored(model="claude-opus-5-5")
@@ -186,15 +188,15 @@ def test_virtual_memory_resource_peers(vmm_ipc_device_x2):
186188
pytest.skip("Test requires peer access from the second device to the first")
187189
mr = _vmm_resource(dev0, peers=(dev1.device_id,))
188190
buf = mr.allocate(NBYTES)
189-
_fill(dev0, buf)
190-
191-
report = _send_to_child(buf, visible=(dev1, dev0))
192-
_check_report(report, dev0)
193-
assert report["peer_uuids"] == [dev1.uuid]
194-
assert report["peer_access"] == [3]
195-
196-
buf.close()
197-
dev0.sync()
191+
try:
192+
_fill(dev0, buf)
193+
report = _send_to_child(buf, visible=(dev1, dev0))
194+
_check_report(report, dev0)
195+
assert report["peer_uuids"] == [dev1.uuid]
196+
assert report["peer_access"] == [3]
197+
finally:
198+
buf.close()
199+
dev0.sync()
198200

199201

200202
@pytest.mark.agent_authored(model="claude-opus-5-5")
@@ -207,18 +209,18 @@ def test_virtual_memory_resource_peers_from_generator(vmm_ipc_device_x2):
207209
mr = _vmm_resource(dev0, peers=(peer for peer in (dev1.device_id,)))
208210
first = mr.allocate(NBYTES)
209211
buf = mr.allocate(NBYTES)
210-
_fill(dev0, buf)
211-
assert _access_flags(first, dev1.device_id) == 3
212-
assert _access_flags(buf, dev1.device_id) == 3
213-
214-
report = _send_to_child(buf, visible=(dev1, dev0))
215-
_check_report(report, dev0)
216-
assert report["peer_uuids"] == [dev1.uuid]
217-
assert report["peer_access"] == [3]
218-
219-
first.close()
220-
buf.close()
221-
dev0.sync()
212+
try:
213+
_fill(dev0, buf)
214+
assert _access_flags(first, dev1.device_id) == 3
215+
assert _access_flags(buf, dev1.device_id) == 3
216+
report = _send_to_child(buf, visible=(dev1, dev0))
217+
_check_report(report, dev0)
218+
assert report["peer_uuids"] == [dev1.uuid]
219+
assert report["peer_access"] == [3]
220+
finally:
221+
first.close()
222+
buf.close()
223+
dev0.sync()
222224

223225

224226
@pytest.mark.agent_authored(model="claude-opus-5-5")

0 commit comments

Comments
 (0)