Skip to content

Fix ToDlPack memory space classification for offset views - #1238

Merged
cliffburdick merged 11 commits into
NVIDIA:mainfrom
lennartvoelz:bug/fix_ToDlPack
Aug 26, 2026
Merged

Fix ToDlPack memory space classification for offset views#1238
cliffburdick merged 11 commits into
NVIDIA:mainfrom
lennartvoelz:bug/fix_ToDlPack

Conversation

@lennartvoelz

Copy link
Copy Markdown
Contributor

Fixes Issue #1235

Fix

Classify from the storage base pointer instead of from the possibly offset data pointer.
The exported tensor is unchaned, so dl_tensor.data is still the views offset pointer. Only the memory probe is moved to the base pointer of the underlying storage.

Changes

  • include/matx/core/tensor.h: ToDlPackImpl() classifies from GetStorage().data(); GetStorage() made const so a const tensor can be exported
  • include/matx/core/print.h: same defect in PrintData(), same fix
  • include/matx/core/allocator.h: GetPointerKind()'s doc comment described an approximate "next lowest address" lookup that the implementation does not do. Rewritten to state the actual contract: exact match, base pointer required, MATX_INVALID_MEMORY on a miss

Testing

DLPackTestsAll.ExportOffsetSlice and .ExportPermutedOffsetSlice, over MatXAllTypesCUDAExec and all five memory spaces, covering both the legacy and versioned export paths; each asserts the exported device type, dtype, shape and strides, that data is the view's offset pointer with byte_offset == 0, and that the storage refcount returns to its pre-export value after deleter().

Verification

test_00_tensor_DLPackTests: 84 passed.
Confirmed the tests actually pin the fix: reverting ToDlPackImpl() to this->Data() fails 26 cases across ExportOffsetSlice and ExportPermutedOffsetSlice.

lennartvoelz and others added 5 commits August 25, 2026 16:17
The comment described that it performs a next address approximation on
the input pointer. This is not what the implementation does. Instead, it
performs an exact lookup with the key being the input pointer. Thus, the
base pointer of the tensor needs to be passed in.
- make GetStorage const
- use tensor_t::GetStorage::data instead of tensor_t::Data as the input
for GetPointerKind in order to make the memory space lookup possible
with Slice/Permutation views
- Add DLPackTestsAll.ExportOffsetSlice and ExportPermutedOffsetSlice to
  cover views whose internal data pointer is offset from the base pointer
- GetPointerKind is an exact address lookup, so an offset pointer is
  never found, so ToDlPack must use the base pointer to classify the
  memory space
- Refactor the per memory space loop into a shared helper
@copy-pr-bot

copy-pr-bot Bot commented Aug 26, 2026

Copy link
Copy Markdown

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.

Rewords the note about base-pointer-only lookups and removes the
stale mention of a previously-supported approximate lookup.
tensor_impl_t and dynamic_tensor_t don't expose GetStorage(), so the
direct op.GetStorage().data() call in PrintData didn't compile for
those types. GetStorageBasePointer() falls back to op.Data() for them
via a requires-clause, while still passing the true base pointer for
types that do carry storage.
The existing GetStorage() returns storage_ by value, bumping the
shared buffer's reference count on every call. Callers that only need
to read through storage (e.g. GetStorageBasePointer() in print.h) can
now bind to a const tensor and get a reference instead. The non-const
overload keeps returning a copy for callers that need to hand
ownership elsewhere (make_tensor(), sparse tensor constructors).
Covers the two shapes PrintData() must classify: a slice whose Data()
is offset into its allocation, and tensor_impl_t, which carries no
storage and must fall back to Data(). The tensor_impl_t case guards
against the build regression GetStorageBasePointer() fixes.
RealView()/ImagView() build their own non-owning storage at the
offset/reinterpreted pointer instead of sharing the source tensor's
storage_, so GetStorage().data() on the result never resolves to the
allocation's true base. ToDlPackImpl's allocator-map lookup always
misses for them and falls back to cuPointerGetAttributes, but that
fallback only checked CU_MEMORYTYPE_DEVICE and dumped everything else
(including genuinely pinned host memory) into kDLCPU.

Verified empirically (probe against the driver API on this Jetson
target) that CU_POINTER_ATTRIBUTE_IS_MANAGED distinguishes managed
memory from pinned host memory, both of which report
CU_MEMORYTYPE_HOST via CU_POINTER_ATTRIBUTE_MEMORY_TYPE alone. The
fallback now checks both attributes and classifies exactly like the
exact-match path: managed/device -> kDLCUDA, pinned host ->
kDLCUDAHost, else -> kDLCPU.

Also documents on RealView()/ImagView() why they always hit this
fallback path rather than the allocator-map lookup.
Covers the fallback path ToDlPackImpl() takes for RealView()/ImagView():
their non-owning storage never resolves to the allocation's true base,
so GetPointerKind()'s exact-match lookup always misses and
cuPointerGetAttributes must classify the memory instead. Slicing first
guarantees both views start at a non-zero offset, exercising the fix
across all five exportable memory spaces.
@lennartvoelz
lennartvoelz marked this pull request as ready for review August 26, 2026 11:28
@greptile-apps

greptile-apps Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR corrects memory-space classification for offset tensor views while preserving the exported view pointer and metadata.

  • Uses the underlying storage pointer when classifying DLPack exports and printable tensor views.
  • Improves CUDA fallback classification for managed and pinned-host memory.
  • Documents the allocator’s exact-address lookup contract and adds offset, permuted, complex-component, memory-space, and lifetime coverage.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The implementation separates the exported offset data pointer from the allocation pointer used for memory classification, preserves DLPack shape, stride, and lifetime behavior, and retains fallback handling for views whose storage pointer is not an allocator-recorded base.

Important Files Changed

Filename Overview
include/matx/core/tensor.h Classifies DLPack exports from the storage pointer, preserves the offset view pointer in the capsule, and extends CUDA fallback handling without an accepted regression.
include/matx/core/print.h Adds generic storage-base selection for printing while retaining a Data() fallback for tensor types without storage access.
include/matx/core/allocator.h Corrects documentation to match the allocator’s existing exact-address lookup behavior.
test/00_tensor/DLPackTests.cu Adds broad legacy and versioned DLPack coverage across offset views, permutations, component views, memory spaces, metadata, and ownership cleanup.
test/00_operators/print_test.cu Adds compile and execution coverage for offset tensor views and storage-less tensor_impl_t printing.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  V[Tensor offset view] --> D[Export Data pointer]
  V --> S[Underlying storage base pointer]
  S --> M[Allocator memory-space lookup]
  M --> T[DLPack device metadata]
  D --> C[DLPack consumer]
  T --> C
Loading

Reviews (1): Last reviewed commit: "Add DLPack export test for RealView()/Im..." | Re-trigger Greptile

@cliffburdick

Copy link
Copy Markdown
Collaborator

/build

@coveralls

Copy link
Copy Markdown

Coverage Status

Coverage is 93.399%lennartvoelz:bug/fix_ToDlPack into NVIDIA:main. No base build found for NVIDIA:main.

@cliffburdick
cliffburdick merged commit 4feaa9f into NVIDIA:main Aug 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants