Skip to content

Commit 9bf37ed

Browse files
committed
Avoid freeing failed VMM grow reservation
1 parent e4208ed commit 9bf37ed

2 files changed

Lines changed: 112 additions & 4 deletions

File tree

cuda_core/cuda/core/_memory/_virtual_memory_resource.py

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

268-
if res != driver.CUresult.CUDA_SUCCESS or new_ptr != (int(buf.handle) + aligned_prev_size):
268+
expected_ptr = int(buf.handle) + aligned_prev_size
269+
if res != driver.CUresult.CUDA_SUCCESS:
269270
# Check for specific errors that are not recoverable with the slow path
270271
if res in (
271272
driver.CUresult.CUDA_ERROR_INVALID_VALUE,
@@ -274,15 +275,21 @@ def modify_allocation(
274275
driver.CUresult.CUDA_ERROR_NOT_SUPPORTED,
275276
):
276277
raise_if_driver_error(res)
278+
# Fallback: couldn't reserve contiguously, need full remapping
279+
return self._grow_allocation_slow_path(
280+
buf, new_size, prop, aligned_additional_size, total_aligned_size, addr_align
281+
)
282+
283+
if new_ptr != expected_ptr:
277284
(res2,) = driver.cuMemAddressFree(new_ptr, aligned_additional_size)
278285
raise_if_driver_error(res2)
279286
# Fallback: couldn't extend contiguously, need full remapping
280287
return self._grow_allocation_slow_path(
281288
buf, new_size, prop, aligned_additional_size, total_aligned_size, addr_align
282289
)
283-
else:
284-
# Success! We can extend the VA range contiguously
285-
return self._grow_allocation_fast_path(buf, new_size, prop, aligned_additional_size, new_ptr)
290+
291+
# Success! We can extend the VA range contiguously
292+
return self._grow_allocation_fast_path(buf, new_size, prop, aligned_additional_size, new_ptr)
286293

287294
def _grow_allocation_fast_path(
288295
self, buf: Buffer, new_size: int, prop: driver.CUmemAllocationProp, aligned_additional_size: int, new_ptr: int

cuda_core/tests/test_memory.py

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

10371037

1038+
def _make_mock_vmm_resource():
1039+
vmm_mr = VirtualMemoryResource.__new__(VirtualMemoryResource)
1040+
vmm_mr.device = type("FakeDevice", (), {"device_id": 0})()
1041+
vmm_mr.config = VirtualMemoryResourceOptions(handle_type="win32_kmt" if IS_WINDOWS else "posix_fd")
1042+
return vmm_mr
1043+
1044+
1045+
def test_vmm_allocator_grow_allocation_does_not_free_failed_adjacent_reservation(monkeypatch):
1046+
vmm_mr = _make_mock_vmm_resource()
1047+
1048+
SUCCESS = driver.CUresult.CUDA_SUCCESS
1049+
ERROR = driver.CUresult.CUDA_ERROR_OUT_OF_MEMORY
1050+
base_ptr = 0x10_0000
1051+
old_size = 2048
1052+
new_size = 4096
1053+
granularity = 1024
1054+
stale_ptr = 0xBAD
1055+
calls = []
1056+
1057+
class FakeBuffer:
1058+
handle = base_ptr
1059+
size = old_size
1060+
1061+
def fake_get_allocation_granularity(_, _granularity_flag):
1062+
calls.append(("granularity",))
1063+
return (SUCCESS, granularity)
1064+
1065+
def fake_addr_reserve(size, align, hint, flags):
1066+
calls.append(("reserve", size, align, hint, flags))
1067+
return (ERROR, stale_ptr)
1068+
1069+
def fake_addr_free(ptr, size):
1070+
calls.append(("addr_free", ptr, size))
1071+
return (SUCCESS,)
1072+
1073+
def fake_slow_path(self, buf, result_size, prop, aligned_additional_size, total_aligned_size, addr_align):
1074+
calls.append(("slow_path", result_size, aligned_additional_size, total_aligned_size, addr_align))
1075+
return buf
1076+
1077+
monkeypatch.setattr(driver, "cuMemGetAllocationGranularity", fake_get_allocation_granularity)
1078+
monkeypatch.setattr(driver, "cuMemAddressReserve", fake_addr_reserve)
1079+
monkeypatch.setattr(driver, "cuMemAddressFree", fake_addr_free)
1080+
monkeypatch.setattr(VirtualMemoryResource, "_grow_allocation_slow_path", fake_slow_path)
1081+
1082+
result = vmm_mr.modify_allocation(FakeBuffer(), new_size)
1083+
1084+
assert isinstance(result, FakeBuffer)
1085+
assert calls == [
1086+
("granularity",),
1087+
("reserve", 2048, granularity, base_ptr + old_size, 0),
1088+
("slow_path", new_size, 2048, 4096, granularity),
1089+
]
1090+
1091+
1092+
def test_vmm_allocator_grow_allocation_frees_noncontiguous_adjacent_reservation(monkeypatch):
1093+
vmm_mr = _make_mock_vmm_resource()
1094+
1095+
SUCCESS = driver.CUresult.CUDA_SUCCESS
1096+
base_ptr = 0x10_0000
1097+
old_size = 2048
1098+
new_size = 4096
1099+
granularity = 1024
1100+
noncontiguous_ptr = base_ptr + 4 * granularity
1101+
calls = []
1102+
1103+
class FakeBuffer:
1104+
handle = base_ptr
1105+
size = old_size
1106+
1107+
def fake_get_allocation_granularity(_, _granularity_flag):
1108+
calls.append(("granularity",))
1109+
return (SUCCESS, granularity)
1110+
1111+
def fake_addr_reserve(size, align, hint, flags):
1112+
calls.append(("reserve", size, align, hint, flags))
1113+
return (SUCCESS, noncontiguous_ptr)
1114+
1115+
def fake_addr_free(ptr, size):
1116+
calls.append(("addr_free", ptr, size))
1117+
return (SUCCESS,)
1118+
1119+
def fake_slow_path(self, buf, result_size, prop, aligned_additional_size, total_aligned_size, addr_align):
1120+
calls.append(("slow_path", result_size, aligned_additional_size, total_aligned_size, addr_align))
1121+
return buf
1122+
1123+
monkeypatch.setattr(driver, "cuMemGetAllocationGranularity", fake_get_allocation_granularity)
1124+
monkeypatch.setattr(driver, "cuMemAddressReserve", fake_addr_reserve)
1125+
monkeypatch.setattr(driver, "cuMemAddressFree", fake_addr_free)
1126+
monkeypatch.setattr(VirtualMemoryResource, "_grow_allocation_slow_path", fake_slow_path)
1127+
1128+
result = vmm_mr.modify_allocation(FakeBuffer(), new_size)
1129+
1130+
assert isinstance(result, FakeBuffer)
1131+
assert calls == [
1132+
("granularity",),
1133+
("reserve", 2048, granularity, base_ptr + old_size, 0),
1134+
("addr_free", noncontiguous_ptr, 2048),
1135+
("slow_path", new_size, 2048, 4096, granularity),
1136+
]
1137+
1138+
10381139
def test_vmm_allocator_rdma_unsupported_exception():
10391140
"""Test that VirtualMemoryResource throws an exception when RDMA is requested but device doesn't support it.
10401141

0 commit comments

Comments
 (0)