Skip to content

Commit 804f709

Browse files
Avoid COW ABI dependency in ATen bridge (#20808)
Summary: - Add a local helper to fetch the mutable ATen tensor storage pointer without calling Tensor::mutable_data_ptr(). - Use it when aliasing ATen tensors into ExecuTorch tensors so rebuilt training pybindings do not depend on C10 COW materializer symbols. - Preserve tensor-view offsets by applying storage_offset() * itemsize(). - Import the XOR model relatively from the XOR exporter, so Android source-tree model export does not load the stale installed training pybinding before the wheel is rebuilt. Why: - _training_lib can fail to import when built against a Torch/C10 ABI exposing materialize_cow_storage but loaded with a newer Torch runtime where that symbol changed. - The Android CI job installs the currently published executorch wheel, so it needs the XOR exporter to avoid importing that stale native training binding while generating test resources from source.
1 parent f4b01a8 commit 804f709

2 files changed

Lines changed: 23 additions & 3 deletions

File tree

extension/aten_util/aten_bridge.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ namespace executorch {
1717
namespace extension {
1818

1919
namespace {
20+
void* mutable_tensor_data_ptr_no_cow(at::Tensor& tensor) {
21+
if (tensor.numel() == 0) {
22+
return nullptr;
23+
}
24+
25+
auto* storage_data = static_cast<char*>(tensor.unsafeGetTensorImpl()
26+
->unsafe_storage()
27+
.unsafeGetStorageImpl()
28+
->_mutable_data_ptr_no_checks()
29+
.mutable_get());
30+
ET_CHECK_MSG(
31+
storage_data != nullptr,
32+
"Tensor has a non-zero number of elements, but its data is not allocated");
33+
return storage_data + tensor.storage_offset() * tensor.itemsize();
34+
}
35+
2036
void check_tensor_meta(const at::Tensor& a, const executorch::aten::Tensor& b) {
2137
// 0-dim (scalar) tensors legitimately have empty sizes/strides arrays;
2238
// their `.data()` may return nullptr depending on the underlying container.
@@ -139,7 +155,8 @@ void alias_etensor_to_attensor(
139155
"Input tensor must have contiguous or channels last memory format");
140156

141157
check_tensor_meta(aten_tensor, mutable_et);
142-
mutable_et.unsafeGetTensorImpl()->set_data(aten_tensor.mutable_data_ptr());
158+
mutable_et.unsafeGetTensorImpl()->set_data(
159+
mutable_tensor_data_ptr_no_cow(aten_tensor));
143160
}
144161

145162
at::Tensor alias_attensor_to_etensor(const torch::executor::Tensor& etensor) {
@@ -163,7 +180,7 @@ at::Tensor alias_attensor_to_etensor(const torch::executor::Tensor& etensor) {
163180
TensorPtr alias_tensor_ptr_to_attensor(at::Tensor& t) {
164181
return make_tensor_ptr(
165182
{t.sizes().begin(), t.sizes().end()},
166-
t.mutable_data_ptr(),
183+
mutable_tensor_data_ptr_no_cow(t),
167184
torch::executor::ScalarType(t.scalar_type()));
168185
}
169186

extension/training/examples/XOR/export_model.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
import torch
1414
from executorch.exir import ExecutorchBackendConfig, to_edge
1515

16-
from executorch.extension.training.examples.XOR.model import Net, TrainingNet
16+
if __package__:
17+
from .model import Net, TrainingNet
18+
else:
19+
from model import Net, TrainingNet
1720
from torch.export import export
1821
from torch.export.experimental import _export_forward_backward
1922

0 commit comments

Comments
 (0)