Skip to content

fix(cuda.core): route pool-backed MR buffers through deallocate() - #2620

Open
atiaomar1978-hub wants to merge 6 commits into
NVIDIA:mainfrom
atiaomar1978-hub:fix/pool-backed-mr-deallocate-2615
Open

fix(cuda.core): route pool-backed MR buffers through deallocate()#2620
atiaomar1978-hub wants to merge 6 commits into
NVIDIA:mainfrom
atiaomar1978-hub:fix/pool-backed-mr-deallocate-2615

Conversation

@atiaomar1978-hub

@atiaomar1978-hub atiaomar1978-hub commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description

closes #2615

Pool-backed memory resources (DeviceMemoryResource, PinnedMemoryResource, ManagedMemoryResource) and GraphMemoryResource previously returned buffers whose C++ deleter called cuMemFreeAsync directly, bypassing Python deallocate() overrides.

This change wraps raw pool/async allocations with MR-owned device pointer handles (the same path as Buffer.from_handle(mr=...)), records the allocation stream at creation, and routes teardown through MemoryResource.deallocate().

Checklist

  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Test plan

  • pytest cuda_core/tests/test_memory.py -k "pool_backed_mr or dmr_deallocate_frees_pool_pointer or dmr_from_handle_deallocate"
  • CI source builds and GPU tests for cuda.core

Pool-backed and graph memory resources now wrap raw allocations with
MR-owned device pointer handles, matching Buffer.from_handle(mr=...).
Subclasses can observe or customize teardown via deallocate().

Fixes NVIDIA#2615

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the cuda.core Everything related to the cuda.core module label Aug 13, 2026
atiaomar1978-hub and others added 2 commits August 13, 2026 16:46
Use MR-owned handles only for Python subclasses so built-in pool/graph
MRs retain nogil cuMemFreeAsync teardown during interpreter shutdown.

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Thanks for filing #2615 — this PR addresses the inconsistent deallocation paths.

Approach

  • Python subclasses of pool-backed / graph MRs now wrap allocations with MR-owned handles (deviceptr_create_owned_by_mr), so overridden deallocate() is honored on close() / GC (matching Buffer.from_handle(mr=...)).
  • Built-in types keep the direct C++ cuMemFreeAsync deleter to preserve nogil teardown during interpreter shutdown.

Tests added

  • Subclass deallocate() invoked on close, GC, and with explicit stream (device + pinned pools)
  • Pool byte accounting for mr.allocate() and from_handle paths

Bugbot review: clean after the hybrid approach. Happy to adjust based on maintainer feedback.

Document MemoryResource subclass teardown behavior and add a 1.2.0
release note for pool-backed MR deallocate consistency.

Signed-off-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

GPU test report (RunPod, contributor-run)

I ran the targeted memory tests on a community GPU pod to validate this change outside CI.

Environment

  • GPU: NVIDIA RTX 4000 Ada Generation (community cloud)
  • Image: runpod/pytorch:2.4.0-py3.11-cuda12.4.1-devel-ubuntu22.04
  • Branch: fix/pool-backed-mr-deallocate-2615 (atiaomar1978-hub/cuda-python)
  • Build: editable cuda_core with CUDA 13 headers (cuda-toolkit==13.*, cuda-bindings==13.*, CUDA_CORE_BUILD_MAJOR=13)

Command

pytest cuda_core/tests/test_memory.py \
  -k "pool_backed_mr or dmr_deallocate_frees_pool_pointer or dmr_from_handle_deallocate or deallocate" -v

Results: 11 passed, 2 skipped, 0 failed

Test Result
test_mr_deallocate_called_on_close passed
test_mr_deallocate_called_on_gc passed
test_mr_deallocate_receives_stream passed
test_pool_backed_mr_deallocate_called_on_close[device] passed
test_pool_backed_mr_deallocate_called_on_close[pinned] skipped
test_pool_backed_mr_deallocate_called_on_gc passed
test_pool_backed_mr_deallocate_receives_stream passed
test_mr_deallocate_raises_on_driver_error passed
test_pool_buffer_deallocates_without_current_context passed
test_pool_buffer_deallocates_with_foreign_context skipped
test_synchronous_memory_resource_deallocate_accepts_stream passed
test_dmr_deallocate_frees_pool_pointer passed
test_dmr_from_handle_deallocate_frees_pool_pointer passed

The two skips look environment-specific (pinned pool path and foreign-context teardown) and are not failures.

Note: the host driver reported CUDA 12 while bindings were built for CUDA 13; tests still passed. Upstream CI with a matched driver/toolkit should be the authoritative run.

This covers the test plan items in the PR description for the pool-backed MR / deallocate() routing behavior.

atiaomar1978-hub and others added 2 commits August 14, 2026 17:48
Update stubgen-pyx output after docstring changes for pre-commit.ci
on PR NVIDIA#2620.

Signed-off-by: Omar Atie <atiaomar1978@gmail.com>
Bring branch up to date with upstream main (including NVIDIA#2624 test helper
refactor) without rewriting PR commit history.
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Branch update + RunPod validation (post-merge with main)

Per maintainer preference, merged main into the branch (merge commit e8ecfac719) instead of rebasing/force-pushing, so existing PR commit history is preserved. This picks up #2624 (Andy’s make_instrumented_memory_resource test helper refactor) and other recent main changes.

RunPod GPU tests

Pod: RTX 4000 Ada (community), runpod/pytorch:2.4.0-py3.11-cuda12.4.1-devel-ubuntu22.04
Branch: fix/pool-backed-mr-deallocate-2615 @ e8ecfac719
Build: editable cuda_core with CUDA 13.3 toolkit headers + cuda-bindings==13.*

tests/test_memory.py (271 tests)

141 passed, 95 failed, 35 skipped

All #2615 regression tests passed:

Test Result
test_pool_backed_mr_deallocate_called_on_close[device] passed
test_pool_backed_mr_deallocate_called_on_close[pinned] skipped
test_pool_backed_mr_deallocate_called_on_gc passed
test_pool_backed_mr_deallocate_receives_stream passed
test_mr_deallocate_called_on_close passed
test_mr_deallocate_called_on_gc passed
test_mr_deallocate_receives_stream passed
test_dmr_deallocate_frees_pool_pointer passed
test_dmr_from_handle_deallocate_frees_pool_pointer passed

The 95 failures are environmental, not regressions from this PR: cudaErrorInsufficientDriver / missing driver symbols because the pod’s NVIDIA driver supports CUDA 12 while we built against CUDA 13 bindings (required after merging current main). Managed-memory and related tests hit this mismatch.

Full cuda_core/tests/ collection also needs extra test deps (pytest-flaky, etc.) and a CUDA-13-capable driver for a clean run — upstream CI is the authoritative full-suite gate.

Pod terminated after testing.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

RunPod validation (post-merge with main)

Re-ran the PR-targeted memory tests after merge commit e8ecfac719 (main merged into branch, history preserved).

Environment

  • GPU: NVIDIA RTX A4000 (driver 560.35.03)
  • Branch: fix/pool-backed-mr-deallocate-2615 @ e8ecfac719
  • Build: editable cuda_core with CUDA 13.3 toolkit + cuda-bindings==13.*

Command

pytest tests/test_memory.py \
  -k "pool_backed_mr or dmr_deallocate_frees_pool_pointer or dmr_from_handle_deallocate or deallocate" -v

Result: 11 passed, 2 skipped, 0 failed

Test Result
test_pool_backed_mr_deallocate_called_on_close[device] passed
test_pool_backed_mr_deallocate_called_on_close[pinned] skipped
test_pool_backed_mr_deallocate_called_on_gc passed
test_pool_backed_mr_deallocate_receives_stream passed
test_mr_deallocate_called_on_close passed
test_mr_deallocate_called_on_gc passed
test_mr_deallocate_receives_stream passed
test_dmr_deallocate_frees_pool_pointer passed
test_dmr_from_handle_deallocate_frees_pool_pointer passed

All #2615 regression tests pass after merging main (including #2624 test helper refactor). Pod terminated after the run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuda.core Everything related to the cuda.core module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pool-backed MemoryResource buffers bypass overridden deallocate() methods

1 participant