|
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
4 | 4 | import ctypes |
| 5 | +import functools |
5 | 6 | import multiprocessing as mp |
6 | 7 | import sys |
7 | 8 |
|
@@ -1506,37 +1507,46 @@ def __init__(self, size): |
1506 | 1507 | assert ("release", NEW_HANDLE) in calls |
1507 | 1508 |
|
1508 | 1509 |
|
| 1510 | +def _vmm_allocate_and_close(mr, requested_size, grow): |
| 1511 | + buf = mr.allocate(requested_size) |
| 1512 | + if grow: |
| 1513 | + buf = mr.modify_allocation(buf, 2 * buf.size) |
| 1514 | + aligned_size = buf.size |
| 1515 | + buf.close() |
| 1516 | + return aligned_size |
| 1517 | + |
| 1518 | + |
| 1519 | +@functools.cache |
| 1520 | +def _warm_up_vmm_allocate_and_close(device_id, grow): |
| 1521 | + device = Device(device_id) |
| 1522 | + mr = VirtualMemoryResource( |
| 1523 | + device, |
| 1524 | + config=VirtualMemoryResourceOptions(handle_type="win32_kmt" if IS_WINDOWS else "posix_fd"), |
| 1525 | + ) |
| 1526 | + return _vmm_allocate_and_close(mr, 8 * 1024 * 1024, grow) |
| 1527 | + |
| 1528 | + |
1509 | 1529 | @pytest.mark.thread_unsafe(reason="cuMemGetInfo measures process-wide free memory") |
1510 | 1530 | @pytest.mark.parametrize("grow", [False, True], ids=["allocate", "grow"]) |
1511 | 1531 | def test_vmm_allocate_close_does_not_leak(init_cuda, grow): |
1512 | 1532 | device = Device() |
1513 | 1533 | if not device.properties.virtual_memory_management_supported: |
1514 | 1534 | pytest.skip("Virtual memory management is not supported on this device") |
1515 | 1535 |
|
| 1536 | + aligned_size = _warm_up_vmm_allocate_and_close(device.device_id, grow) |
1516 | 1537 | mr = VirtualMemoryResource( |
1517 | 1538 | device, |
1518 | 1539 | config=VirtualMemoryResourceOptions(handle_type="win32_kmt" if IS_WINDOWS else "posix_fd"), |
1519 | 1540 | ) |
1520 | 1541 | requested_size = 8 * 1024 * 1024 |
1521 | 1542 |
|
1522 | | - def allocate_and_close(): |
1523 | | - buf = mr.allocate(requested_size) |
1524 | | - if grow: |
1525 | | - buf = mr.modify_allocation(buf, 2 * buf.size) |
1526 | | - aligned_size = buf.size |
1527 | | - buf.close() |
1528 | | - return aligned_size |
1529 | | - |
1530 | | - aligned_size = allocate_and_close() # Warm up and learn the aligned allocation size. |
1531 | | - |
1532 | 1543 | baseline = handle_return(driver.cuMemGetInfo())[0] |
1533 | 1544 | for _ in range(8): |
1534 | | - allocate_and_close() |
| 1545 | + _vmm_allocate_and_close(mr, requested_size, grow) |
1535 | 1546 | free = handle_return(driver.cuMemGetInfo())[0] |
1536 | 1547 |
|
1537 | | - # The broken path leaks aligned_size per iteration. Allow one allocation's |
1538 | | - # worth of driver bookkeeping/caching while still detecting repeated leaks. |
1539 | | - assert baseline - free < 2 * aligned_size |
| 1548 | + # A leak would cost at least one allocation per iteration. |
| 1549 | + assert baseline - free < aligned_size |
1540 | 1550 |
|
1541 | 1551 |
|
1542 | 1552 | def test_vmm_allocator_rdma_unsupported_exception(): |
|
0 commit comments