-
Notifications
You must be signed in to change notification settings - Fork 25
Open
Description
dpnp_array.data.ptr always returns the base USM allocation pointer for views/slices, ignoring the offset tracked internally by dpctl.tensor.usm_ndarray. This means arr[0].data.ptr == arr[1].data.ptr for any multi-dimensional array, making it impossible to pass correct device pointers to external kernels via .data.ptr.
This is related to but distinct from a recent issue #2641. That issue covered dpnp.ndarray(shape, buffer=usm_memory_obj) dropping the offset during construction. This issue is about .data.ptr not reflecting offsets on any view, even when the underlying dpctl layer tracks them correctly.
A big shoutout to AI for helping with several cases!
Reproducer:
import dpnp
import dpctl.tensor as dpt
import numpy as np
comp = 4
nao_max = 50
nao_sub = 30
MIN_BLK_SIZE = 4096
ngrids = MIN_BLK_SIZE # ip1 - ip0 == full block for simplicity
def ptr(a):
return int(a.data.ptr)
def usm_offset(a):
if hasattr(a, '__sycl_usm_array_interface__'):
return a.__sycl_usm_array_interface__.get('offset', 0)
return 'N/A'
def check_views(label, arr):
print(f"\n=== {label} ===")
print(f" shape = {arr.shape}")
print(f" dtype = {arr.dtype}")
print(f" data.ptr = {hex(ptr(arr))}")
print(f" USM offset = {usm_offset(arr)}")
print(f" arr[0].data.ptr = {hex(ptr(arr[0]))}")
if arr.shape[0] > 1:
print(f" arr[1].data.ptr = {hex(ptr(arr[1]))}")
expected_diff = arr.shape[1] * arr.shape[2] * arr.itemsize
actual_diff = ptr(arr[1]) - ptr(arr[0])
print(f" arr[0]==arr[1]? {ptr(arr[0]) == ptr(arr[1])}")
print(f" expected diff = {expected_diff}")
print(f" actual diff = {actual_diff}")
print(f" CORRECT? {'YES' if actual_diff == expected_diff else 'NO -- BUG!'}")
# ── The original allocation (like buf = cupy.empty(...)) ──
buf = dpnp.empty((comp, nao_max, MIN_BLK_SIZE), dtype=dpnp.float64, order='C')
print(f"buf.shape = {buf.shape}, buf.data.ptr = {hex(ptr(buf))}")
print(f"type(buf.data) = {type(buf.data)}")
shape = (comp, nao_sub, ngrids)
# ── Test 1: dpnp.ndarray(shape, buffer=buf.data) [the broken pattern] ──
out1 = dpnp.ndarray(shape, dtype=buf.dtype, buffer=buf.data)
check_views("Test 1: dpnp.ndarray(shape, buffer=buf.data)", out1)
# ── Test 2: dpnp.ndarray(shape, buffer=buf) [the working pattern] ──
out2 = dpnp.ndarray(shape, dtype=buf.dtype, buffer=buf)
check_views("Test 2: dpnp.ndarray(shape, buffer=buf)", out2)
# ── Test 3: flat + reshape via dpnp ──
flat_size = comp * nao_sub * ngrids
flat3 = dpnp.ndarray((flat_size,), dtype=buf.dtype, buffer=buf.data)
out3 = flat3.reshape(shape)
check_views("Test 3: flat dpnp(buffer=buf.data).reshape()", out3)
# ── Test 4: flat dpnp + dpnp.ndarray(shape, buffer=flat) ──
flat4 = dpnp.ndarray((flat_size,), dtype=buf.dtype, buffer=buf.data)
out4 = dpnp.ndarray(shape, dtype=buf.dtype, buffer=flat4)
check_views("Test 4: dpnp.ndarray(shape, buffer=flat_dpnp)", out4)
# ── Test 5: dpctl.tensor direct construction ──
usm5 = dpt.usm_ndarray(shape, dtype=dpt.float64, buffer=buf.data)
print(f"\n=== Test 5: dpctl.tensor.usm_ndarray(shape, buffer=buf.data) ===")
print(f" shape = {usm5.shape}")
v0 = usm5[0]
v1 = usm5[1]
print(f" usm[0] offset = {v0.__sycl_usm_array_interface__.get('offset', 0)}")
print(f" usm[1] offset = {v1.__sycl_usm_array_interface__.get('offset', 0)}")
print(f" usm[0] data[0] = {hex(v0.__sycl_usm_array_interface__['data'][0])}")
print(f" usm[1] data[0] = {hex(v1.__sycl_usm_array_interface__['data'][0])}")
expected_diff = nao_sub * ngrids * buf.itemsize
offset_diff = (v1.__sycl_usm_array_interface__.get('offset', 0) -
v0.__sycl_usm_array_interface__.get('offset', 0)) * buf.itemsize
data_diff = (v1.__sycl_usm_array_interface__['data'][0] -
v0.__sycl_usm_array_interface__['data'][0])
total_diff = offset_diff + data_diff
print(f" expected byte diff = {expected_diff}")
print(f" total byte diff = {total_diff} (data_diff={data_diff}, offset_diff={offset_diff})")
print(f" CORRECT? {'YES' if total_diff == expected_diff else 'NO -- BUG!'}")
# ── Test 6: dpctl construct + wrap in dpnp ──
usm6 = dpt.usm_ndarray(shape, dtype=dpt.float64, buffer=buf.data)
out6 = dpnp.dpnp_array.dpnp_array._create_from_usm_ndarray(usm6)
check_views("Test 6: dpctl usm_ndarray -> dpnp wrap", out6)
# ── Test 7: dpctl flat + reshape ──
flat_usm7 = dpt.usm_ndarray((flat_size,), dtype=dpt.float64, buffer=buf.data)
shaped_usm7 = dpt.reshape(flat_usm7, shape)
print(f"\n=== Test 7: dpctl flat + dpt.reshape ===")
v0 = shaped_usm7[0]
v1 = shaped_usm7[1]
print(f" shaped[0] offset = {v0.__sycl_usm_array_interface__.get('offset', 0)}")
print(f" shaped[1] offset = {v1.__sycl_usm_array_interface__.get('offset', 0)}")
offset_diff = (v1.__sycl_usm_array_interface__.get('offset', 0) -
v0.__sycl_usm_array_interface__.get('offset', 0)) * buf.itemsize
data_diff = (v1.__sycl_usm_array_interface__['data'][0] -
v0.__sycl_usm_array_interface__['data'][0])
total_diff = offset_diff + data_diff
print(f" expected byte diff = {expected_diff}")
print(f" total byte diff = {total_diff}")
print(f" CORRECT? {'YES' if total_diff == expected_diff else 'NO -- BUG!'}")
# wrap in dpnp
out7 = dpnp.dpnp_array.dpnp_array._create_from_usm_ndarray(shaped_usm7)
check_views("Test 7b: dpctl flat+reshape -> dpnp wrap", out7)
# ── Summary ──
print("\n" + "="*60)
print("SUMMARY")
print("="*60)
for label, arr in [
("Test 1: buffer=buf.data", out1),
("Test 2: buffer=buf", out2),
("Test 3: flat(buf.data).reshape", out3),
("Test 4: ndarray(shape, buffer=flat)", out4),
("Test 6: dpctl->dpnp wrap", out6),
("Test 7b: dpctl flat+reshape->dpnp", out7),
]:
if arr.shape[0] > 1:
diff = ptr(arr[1]) - ptr(arr[0])
expected = arr.shape[1] * arr.shape[2] * arr.itemsize
ok = "OK" if diff == expected else "BROKEN"
print(f" {label:40s} ptr diff={diff:>10d} expected={expected:>10d} [{ok}]")output:
$ python3 ./test_dpnp_issuedataptr.py
buf.shape = (4, 50, 4096), buf.data.ptr = 0xff00000000200000
type(buf.data) = <class 'dpnp.memory._memory.MemoryUSMDevice'>
=== Test 1: dpnp.ndarray(shape, buffer=buf.data) ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff00000000200000
arr[0]==arr[1]? True
expected diff = 983040
actual diff = 0
CORRECT? NO -- BUG!
=== Test 2: dpnp.ndarray(shape, buffer=buf) ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff000000002f0000
arr[0]==arr[1]? False
expected diff = 983040
actual diff = 983040
CORRECT? YES
=== Test 3: flat dpnp(buffer=buf.data).reshape() ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff00000000200000
arr[0]==arr[1]? True
expected diff = 983040
actual diff = 0
CORRECT? NO -- BUG!
=== Test 4: dpnp.ndarray(shape, buffer=flat_dpnp) ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff00000000200000
arr[0]==arr[1]? True
expected diff = 983040
actual diff = 0
CORRECT? NO -- BUG!
=== Test 5: dpctl.tensor.usm_ndarray(shape, buffer=buf.data) ===
shape = (4, 30, 4096)
usm[0] offset = 0
usm[1] offset = 122880
usm[0] data[0] = 0xff00000000200000
usm[1] data[0] = 0xff00000000200000
expected byte diff = 983040
total byte diff = 983040 (data_diff=0, offset_diff=983040)
CORRECT? YES
=== Test 6: dpctl usm_ndarray -> dpnp wrap ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff00000000200000
arr[0]==arr[1]? True
expected diff = 983040
actual diff = 0
CORRECT? NO -- BUG!
=== Test 7: dpctl flat + dpt.reshape ===
shaped[0] offset = 0
shaped[1] offset = 122880
expected byte diff = 983040
total byte diff = 983040
CORRECT? YES
=== Test 7b: dpctl flat+reshape -> dpnp wrap ===
shape = (4, 30, 4096)
dtype = float64
data.ptr = 0xff00000000200000
USM offset = 0
arr[0].data.ptr = 0xff00000000200000
arr[1].data.ptr = 0xff00000000200000
arr[0]==arr[1]? True
expected diff = 983040
actual diff = 0
CORRECT? NO -- BUG!
============================================================
SUMMARY
============================================================
Test 1: buffer=buf.data ptr diff= 0 expected= 983040 [BROKEN]
Test 2: buffer=buf ptr diff= 983040 expected= 983040 [OK]
Test 3: flat(buf.data).reshape ptr diff= 0 expected= 983040 [BROKEN]
Test 4: ndarray(shape, buffer=flat) ptr diff= 0 expected= 983040 [BROKEN]
Test 6: dpctl->dpnp wrap ptr diff= 0 expected= 983040 [BROKEN]
Test 7b: dpctl flat+reshape->dpnp ptr diff= 0 expected= 983040 [BROKEN]Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels