Skip to content

cuda.core: use torch 2.14+ stable PyObject->Tensor shim, drop upper version cap - #3033

Merged
leofang merged 6 commits into
NVIDIA:mainfrom
leofang:experiment-stable-pyobj-shim
Oct 31, 2026
Merged

leofang merged 6 commits into
NVIDIA:mainfrom
leofang:experiment-stable-pyobj-shim

Conversation

@leofang

@leofang leofang commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Adopt the stable PyObject -> Tensor C ABI shim that landed in PyTorch 2.14 (pytorch/pytorch#183323, merged as b69f7838a7) as the primary path in the cuda.core tensor bridge, keep the existing pyobj_to_aten_handle pointer-arithmetic trick as the fallback for torch 2.3-2.13, and drop the per-release upper version cap now that the shim covers 2.14+.

The shim adds ~200 ns per view_as_torch_tensor call (benchmark below). The upsides are twofold: (1) ABI safety -- we stop depending on the undocumented THPVariable struct layout for new torch versions, and (2) lower maintenance burden -- the upper-version cap bumps we did on every torch release (#2099 and the aborted attempt in #3031 are the two latest examples) are no longer needed, because torch_tensor_from_pyobject is part of torch's stable C ABI contract and any future torch 2.x is covered automatically.

Changes

  1. cuda_core/cuda/core/_tensor_bridge.pyx: resolve torch_tensor_from_pyobject + aoti_torch_delete_tensor_object via dlsym / GetProcAddress on first view_as_torch_tensor call. Dispatch key is symbol presence, not version string:
    • resolved -> stable shim path (owned handle, deleted after metadata reads via try/finally)
    • NULL -> existing pointer-arithmetic fallback (correct for torch 2.3-2.13)
  2. cuda_core/cuda/core/_memoryview.pyx: drop the upper cap in _torch_version_check. Lower bound stays at 2.3 (required for the AOTI metadata functions). On any future torch 2.x the shim path handles it; no more per-release cap bumps.
  3. cuda_core/cuda/core/_tensor_bridge.pyi: regenerated for the two new ctypedefs.

The resolver stubs on Windows target torch_cpu.dll because torch_tensor_from_pyobject and aoti_torch_delete_tensor_object both live in libtorch_cpu, not libtorch_cuda (confirmed via dladdr on 2.15.0+cu132). This mirrors the existing split -- only aoti_torch_get_current_cuda_stream is CUDA-only.

Verification (local)

Env: fresh conda, python 3.12, CUDA 13.4 toolkit, RTX 6000 Ada; release build of cuda-core (pip install --config-settings debug= -e . -- editable builds default to debug=True on Linux); test target cuda_core/tests/test_utils.py -k torch (63 tests: TestViewGPU[torch-*], TestViewCudaArrayInterfaceGPU[torch-*], test_torch_tensor_bridge_dtypes[*], test_ml_dtypes_bfloat16_torch_dlpack).

torch shim symbol path taken tests pass
2.13.0 NULL pointer-arith 63/63
2.14.1 present shim 63/63
2.15.0 present shim 63/63

The ptr/itemsize assertions in test_torch_tensor_bridge_dtypes cover 13 dtypes end-to-end -- if the shim's owned handle disagreed with torch's view of the storage, the tests would catch it.

Benchmark

Same env, same tensor (32×32 float32 CUDA), release build, 2 000 warm-up iterations outside the measurement loop, then 30 outer × 10 000 inner iterations; each outer sample is a time.perf_counter_ns() burst averaged over its 10 k inner calls. Three independent runs per torch version:

torch 2.13.0 (pointer-arith fallback):
  best=495.2 median=504.2 stdev=7.7
  best=511.7 median=521.7 stdev=5.5
  best=536.6 median=544.5 stdev=4.7

torch 2.14.1 (stable shim):
  best=703.7 median=710.4 stdev=4.5
  best=692.6 median=705.4 stdev=5.1
  best=727.6 median=744.5 stdev=5.1

torch 2.15.0 (stable shim):
  best=739.3 median=745.4 stdev=4.8
  best=713.7 median=722.6 stdev=11.6
  best=727.7 median=735.5 stdev=8.9

Fallback band on 2.13 sits roughly where #1894 reported (565 ns on 2.11, same hardware), a touch faster thanks to the Cython-typed StridedMemoryView view arg in 4ac0f820289. Shim band on 2.14 and 2.15 overlap -- stable ABI genuinely holds across the release.

The ~200 ns absolute overhead is C++ work in libtorch: a vtable call into libtorch_python's THPVariable_Unpack, an at::Tensor copy-construct (bumps the storage refcount), and the matching aoti_torch_delete_tensor_object on the way out. It doesn't shrink with Cython optimisation.

Follow-up idea for upstream

The shim returns a new reference. For view_as_torch_tensor we only read metadata off the handle (get_data_ptr, get_sizes, get_strides, get_dtype, get_device_type, get_device_index) and the Python obj outlives the handle, so a borrowed variant that skipped the refcount bump would be functionally equivalent and would close the perf gap. Worth asking upstream for a torch_tensor_borrow_from_pyobject (or a borrow flag on the existing shim) in a follow-up.

-- Leo's bot

PyTorch >= 2.14 exposes torch_tensor_from_pyobject /
aoti_torch_delete_tensor_object as part of the stable C ABI (landed via
pytorch/pytorch#183323).  These let us obtain an AtenTensorHandle from a
Python tensor object without peering at THPVariable's internal layout.

Dispatch is driven by *symbol presence* via dlsym / GetProcAddress on
first call to view_as_torch_tensor:
  - resolved -> primary path (owned handle, deleted after metadata reads)
  - NULL     -> fall back to the existing pyobj_to_aten_handle
                pointer-arithmetic trick, which stays correct for
                torch 2.3-2.13 (the only versions where this matters).

The outer version gate in _memoryview.pyx (``2.3 <= torch <= 2.14``) is
unchanged -- it still bounds the fallback.  Once we drop support for
torch < 2.14 we can remove the upper bound entirely because the shim
itself is part of torch's stable ABI contract.

Diagnostics kept module-private:
  - _get_pyobj_path_counts() / _reset_pyobj_path_counts()
  - _get_shim_available()
  - _set_use_shim(bool) to force the fallback for A/B benchmarking.
@copy-pr-bot

copy-pr-bot Bot commented Oct 6, 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 Oct 6, 2026
@rparolin rparolin added this to the cuda.core next milestone Oct 8, 2026
…bj-shim

# Conflicts:
#	cuda_core/cuda/core/_tensor_bridge.pyx
Keeps the 2.3 lower bound (required for the AOTI metadata functions).
The dispatch in _tensor_bridge.view_as_torch_tensor now picks between:

  * torch >= 2.14 -- stable torch_tensor_from_pyobject shim
    (pytorch/pytorch#183323; part of torch's stable C ABI contract)
  * torch 2.3 - 2.13 -- pyobj_to_aten_handle pointer-arithmetic,
    validated against the two known THPVariable layouts

Future torch releases >= 2.14 are automatically covered by the shim,
removing the per-release cap bump treadmill.
@leofang leofang added the enhancement Any code-related improvements label Oct 30, 2026
@leofang leofang added the P1 Medium priority - Should do label Oct 30, 2026
@leofang
leofang marked this pull request as ready for review October 30, 2026 02:45
@leofang
leofang requested a review from seberg October 30, 2026 02:45
@leofang

leofang commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/ok to test 87cadd6

@copy-pr-bot

copy-pr-bot Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

/ok to test 87cadd6

@leofang, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@leofang

leofang commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

/ok to test 87cadd6

@leofang leofang changed the title cuda.core: experiment with torch 2.14+ stable PyObject->Tensor shim cuda.core: use torch 2.14+ stable PyObject->Tensor shim, drop upper version cap Oct 30, 2026
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

📝 Summary

Summary by CodeRabbit

  • Compatibility
    • Expanded PyTorch version support to include versions 2.14 and later, alongside versions 2.3–2.13.
  • Bug Fixes
    • Improved tensor-view handling across supported PyTorch versions, including cleanup of temporary tensor resources and continued fallback behavior when the preferred conversion is unavailable.

The PyTorch version check now accepts versions at or above 2.3. The tensor bridge resolves stable conversion and deletion shims at runtime, uses them when both are available, and deletes owned handles after view processing.

Changes: PyTorch tensor bridge

Layer / File(s) Summary
Version support and tensor handle flow
cuda_core/cuda/core/_memoryview.pyx, cuda_core/cuda/core/_tensor_bridge.pyi, cuda_core/cuda/core/_tensor_bridge.pyx
The version check accepts PyTorch 2.3 and later. The bridge adds callback types and platform-specific shim resolution. When both shims resolve, it creates an owned handle and deletes it in a finally block; otherwise it uses pointer arithmetic.

Possibly related PRs

  • NVIDIA/cuda-python#3163: Raises the custom PyTorch sample requirement to 2.14.1, which exercises the stable shim path described here.

Suggested reviewers: juenglin, mdboom

Priority: Normal

Change: Feature

Merge Risk: Low · up to 87cad

Tensor conversion remains usable when the shims resolve, but a missing shim on newer PyTorch can select an unvalidated fallback. Guard that path before merging, or explicitly accept the compatibility risk.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


Review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 03b4153 and 87cadd6.

Files selected for processing: 3
  • cuda_core/cuda/core/_memoryview.pyx
  • cuda_core/cuda/core/_tensor_bridge.pyi
  • cuda_core/cuda/core/_tensor_bridge.pyx

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

Comment thread cuda_core/cuda/core/_tensor_bridge.pyx Resolved
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor
Doc Preview CI
Preview removed because the pull request was closed or merged.

@rwgk rwgk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The finding is only a concern for free-threading. Do you want to fix the race situation in this PR?

codex GPT-6.1-Sol ultra:

One finding at 87cadd6:

[P2] Synchronize the shim cache initialization — _tensor_bridge.pyx:409–412. Concurrent first conversions on free-threaded Python read and write three unsynchronized C globals, creating a C++ data race. PyTorch also declares no-GIL support. Resolve both pointers during module initialization, when torch symbols are already available, or use synchronized initialization.

The CI matrix should also include torch ≥2.14 to exercise the new shim automatically.

The concurrency finding comes from source/generated C++ inspection; no crash was reproduced.

@leofang

leofang commented Oct 31, 2026

Copy link
Copy Markdown
Member Author

It's preexisting so I'll fix it in the next PR. I want to unblock the nightly update (#3031).

@leofang
leofang merged commit 01037b1 into NVIDIA:main Oct 31, 2026
123 checks passed
@leofang
leofang deleted the experiment-stable-pyobj-shim branch October 31, 2026 04:57
@leofang

leofang commented Oct 31, 2026

Copy link
Copy Markdown
Member Author

Thanks, Ralf!

leofang added a commit to leofang/cuda-python that referenced this pull request Oct 31, 2026
PyTorch 2.15.0 ships only as +cu132 on pytorch.org (not cu126/cu130).
Replace the two 2.14.1 rows (cu126 + cu130) per arch with a single
2.15.0+cu132 row.  The 2.9.1 rows (cu126 + cu130) stay as the older
anchor.

The cuda.core tensor-bridge supports torch 2.15 unconditionally after
the stable PyObject->Tensor shim adoption in NVIDIA#3033.
github-actions Bot pushed a commit that referenced this pull request Nov 1, 2026
Removed preview folders for the following PRs:
- PR #3033
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 enhancement Any code-related improvements P1 Medium priority - Should do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants