tensor_parser_aten: tag planned tensor DataPtr with its real device#21289
tensor_parser_aten: tag planned tensor DataPtr with its real device#21289shoumikhin wants to merge 1 commit into
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21289
Note: Links to docs will display an error until the docs builds have been completed. ❌ 1 New FailureAs of commit a17b385 with merge base 8200b9e ( NEW FAILURE - The following job has failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
@shoumikhin has exported this pull request. If you are a Meta employee, you can view the originating Diff in D113384858. |
This PR needs a
|
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect device tagging for planned tensors in ATen-mode deserialization, ensuring that tensors backed by accelerator memory (e.g., CUDA planned buffers) are constructed with consistent device information across the storage DataPtr, TensorImpl device, and dispatch key. It also prevents CUDA backend delegate initialization from clobbering shared-library temp files when identical partitions are loaded multiple times.
Changes:
- Read
device_type/device_indexfromextra_tensor_infoduring ATen tensor parsing and construct tensors viaat::from_blob(..., TensorOptions().device(device), /*target_device=*/device)to keep device tagging consistent. - Preserve the source tensor’s device when sharing tensor storage in
internal::share_tensor_data. - Ensure unique temp
.sopaths in the CUDA backend by adding an atomic counter suffix.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| runtime/executor/tensor_parser_aten.cpp | Parse device metadata and rebuild tensors with correct device tagging via from_blob(..., target_device=...). |
| runtime/core/exec_aten/util/tensor_util_aten.cpp | Preserve device when sharing tensor storage data pointers. |
| backends/cuda/runtime/cuda_backend.cpp | Avoid temp .so path collisions when loading identical CUDA partitions by adding a unique counter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
be429c7 to
23658d4
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
23658d4 to
ec9af03
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
ec9af03 to
4ea0725
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, so sharing a device input's storage keeps its device tag. fbcode and xplat copies kept identical. Differential Revision: D113384858
ee94175 to
cee0a71
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
runtime/executor/tensor_parser_aten.cpp:177
- There is no automated test covering this new ATen-mode device-tagging path (extra_tensor_info->device_type CUDA + from_blob with target_device). The existing tensor_parser_device_test target is only built once (not in an aten_mode variant), so regressions in tensor_parser_aten.cpp (or future PyTorch API changes around from_blob/target_device) would go uncaught. Please add a gtest that builds with USE_ATEN_LIB and asserts that a CUDA-annotated serialized tensor produces an at::Tensor whose (a) storage DataPtr device and (b) tensor.device() both match CUDA (and that missing extra_tensor_info defaults to CPU).
// Rebuild so storage DataPtr, TensorImpl device, and dispatch key agree.
// target_device makes from_blob skip getDeviceFromPtr, so the same path
// works for a real pointer and for a null runtime-bound one.
tensor = at::from_blob(
data_ptr.get(),
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). The serialized device_type is mapped to its ATen counterpart through a small table so validation and conversion share one source of truth and a new device only needs one entry. The untrusted device_type and device_index are validated (unmapped type or a negative accelerator index is rejected), and a non-CPU DYNAMIC_UNBOUND tensor is rejected rather than silently returning CPU-resizable storage that contradicts the serialized device. Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, and verify the destination and source devices match before sharing storage, so a shared tensor cannot end up with a TensorImpl device that disagrees with its DataPtr device. fbcode and xplat copies kept identical. Test Plan: New ATen-mode unit test for the device parsing logic: buck2 test fbcode//executorch/runtime/executor/test:tensor_parser_aten_test Pass 6, fail 0. Covers CPU tensors staying unindexed, missing extra_tensor_info defaulting to CPU, rejection of an unmapped device_type, rejection of a negative accelerator index, rejection of DYNAMIC_UNBOUND on a non-CPU device, and DYNAMIC_UNBOUND still allowed on CPU. ATen-mode load + execute path (the CPU device-index regression this restores): buck2 test fbcode//executorch/extension/module/test:module_test_aten Pass 50, fail 0. This exercises parseTensor followed by aten kernels (e.g. aten::mul.out) on ModuleAddMul; a hardcoded CPU index 0 previously made ATen see cpu vs cpu:0 and abort the kernel, which this fix avoids by keeping CPU unindexed. Unblocks loading a coalesced TRT+CUDA .pte whose CUDA-delegate planned buffers are device memory.
3282ed6 to
804f636
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). The serialized device_type is mapped to its ATen counterpart through a small table so validation and conversion share one source of truth and a new device only needs one entry. The untrusted device_type and device_index are validated (unmapped type or a negative accelerator index is rejected), and a non-CPU DYNAMIC_UNBOUND tensor is rejected rather than silently returning CPU-resizable storage that contradicts the serialized device. Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, and verify the destination and source devices match before sharing storage, so a shared tensor cannot end up with a TensorImpl device that disagrees with its DataPtr device. fbcode and xplat copies kept identical. Test Plan: New ATen-mode unit test for the device parsing logic: buck2 test fbcode//executorch/runtime/executor/test:tensor_parser_aten_test Pass 6, fail 0. Covers CPU tensors staying unindexed, missing extra_tensor_info defaulting to CPU, rejection of an unmapped device_type, rejection of a negative accelerator index, rejection of DYNAMIC_UNBOUND on a non-CPU device, and DYNAMIC_UNBOUND still allowed on CPU. ATen-mode load + execute path (the CPU device-index regression this restores): buck2 test fbcode//executorch/extension/module/test:module_test_aten Pass 50, fail 0. This exercises parseTensor followed by aten kernels (e.g. aten::mul.out) on ModuleAddMul; a hardcoded CPU index 0 previously made ATen see cpu vs cpu:0 and abort the kernel, which this fix avoids by keeping CPU unindexed. Unblocks loading a coalesced TRT+CUDA .pte whose CUDA-delegate planned buffers are device memory.
804f636 to
649f0eb
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). The serialized device_type is mapped to its ATen counterpart through a small table so validation and conversion share one source of truth and a new device only needs one entry. The untrusted device_type and device_index are validated (unmapped type or a negative accelerator index is rejected), and a non-CPU DYNAMIC_UNBOUND tensor is rejected rather than silently returning CPU-resizable storage that contradicts the serialized device. Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, and verify the destination and source devices match before sharing storage, so a shared tensor cannot end up with a TensorImpl device that disagrees with its DataPtr device. fbcode and xplat copies kept identical. Test Plan: New ATen-mode unit test for the device parsing logic: buck2 test fbcode//executorch/runtime/executor/test:tensor_parser_aten_test Pass 6, fail 0. Covers CPU tensors staying unindexed, missing extra_tensor_info defaulting to CPU, rejection of an unmapped device_type, rejection of a negative accelerator index, rejection of DYNAMIC_UNBOUND on a non-CPU device, and DYNAMIC_UNBOUND still allowed on CPU. ATen-mode load + execute path (the CPU device-index regression this restores): buck2 test fbcode//executorch/extension/module/test:module_test_aten Pass 50, fail 0. This exercises parseTensor followed by aten kernels (e.g. aten::mul.out) on ModuleAddMul; a hardcoded CPU index 0 previously made ATen see cpu vs cpu:0 and abort the kernel, which this fix avoids by keeping CPU unindexed. Unblocks loading a coalesced TRT+CUDA .pte whose CUDA-delegate planned buffers are device memory.
649f0eb to
f9432de
Compare
3494a08 to
e433a2a
Compare
…ytorch#21289) Summary: In ATen mode, parseTensor built every planned tensor's storage DataPtr with a hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned buffer) therefore got a CPU-tagged data pointer, so the runtime treated device memory as host memory and the delegate rejected it (Method::init fails in getDeviceFromPtr on a CPU-tagged device pointer). Fix: read the device from the serialized tensor's extra_tensor_info (device_type/device_index, defaulting to CPU when absent, matching the portable parser), then build the tensor with a single at::from_blob(ptr, sizes, strides, /*storage_offset=*/0, deleteNothing, at::TensorOptions().dtype(type).device(device), /*target_device=*/device) so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the dispatch key all agree. Passing target_device makes from_blob skip getDeviceFromPtr, so the same path works for a real device pointer and for a null runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are unchanged (device defaults to CPU). The serialized device_type is mapped to its ATen counterpart through a small table so validation and conversion share one source of truth and a new device only needs one entry. The untrusted device_type and device_index are validated (unmapped type or a negative accelerator index is rejected), and a non-CPU DYNAMIC_UNBOUND tensor is rejected rather than silently returning CPU-resizable storage that contradicts the serialized device. Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the source tensor's device instead of hardcoding CPU, and verify the destination and source devices match before sharing storage, so a shared tensor cannot end up with a TensorImpl device that disagrees with its DataPtr device. fbcode and xplat copies kept identical. Differential Revision: D113384858
e433a2a to
a17b385
Compare
Summary:
In ATen mode, parseTensor built every planned tensor's storage DataPtr with a
hardcoded c10::DeviceType::CPU, and its options with at::CPU(type). A tensor
whose planned buffer lives on an accelerator (e.g. a CUDA-delegate planned
buffer) therefore got a CPU-tagged data pointer, so the runtime treated device
memory as host memory and the delegate rejected it (Method::init fails in
getDeviceFromPtr on a CPU-tagged device pointer).
Fix: read the device from the serialized tensor's extra_tensor_info
(device_type/device_index, defaulting to CPU when absent, matching the portable
parser), then build the tensor with a single
at::from_blob(ptr, sizes, strides, /storage_offset=/0, deleteNothing,
at::TensorOptions().dtype(type).device(device),
/target_device=/device)
so the storage DataPtr, the TensorImpl device (device(), is_cuda()), and the
dispatch key all agree. Passing target_device makes from_blob skip
getDeviceFromPtr, so the same path works for a real device pointer and for a null
runtime-bound pointer without inspecting the pointer. TRT-only / CPU programs are
unchanged (device defaults to CPU).
The serialized device_type is mapped to its ATen counterpart through a small
table so validation and conversion share one source of truth and a new device
only needs one entry. The untrusted device_type and device_index are validated
(unmapped type or a negative accelerator index is rejected), and a non-CPU
DYNAMIC_UNBOUND tensor is rejected rather than silently returning CPU-resizable
storage that contradicts the serialized device.
Also update internal_set_tensor_data (tensor_util_aten.cpp) to preserve the
source tensor's device instead of hardcoding CPU, and verify the destination and
source devices match before sharing storage, so a shared tensor cannot end up
with a TensorImpl device that disagrees with its DataPtr device.
fbcode and xplat copies kept identical.
Test Plan:
New ATen-mode unit test for the device parsing logic:
buck2 test fbcode//executorch/runtime/executor/test:tensor_parser_aten_test
Pass 6, fail 0. Covers CPU tensors staying unindexed, missing extra_tensor_info
defaulting to CPU, rejection of an unmapped device_type, rejection of a negative
accelerator index, rejection of DYNAMIC_UNBOUND on a non-CPU device, and
DYNAMIC_UNBOUND still allowed on CPU.
ATen-mode load + execute path (the CPU device-index regression this restores):
buck2 test fbcode//executorch/extension/module/test:module_test_aten
Pass 50, fail 0. This exercises parseTensor followed by aten kernels (e.g.
aten::mul.out) on ModuleAddMul; a hardcoded CPU index 0 previously made ATen see
cpu vs cpu:0 and abort the kernel, which this fix avoids by keeping CPU unindexed.
Unblocks loading a coalesced TRT+CUDA .pte whose CUDA-delegate planned buffers
are device memory.