@@ -19,6 +19,8 @@ namespace executorch {
1919namespace runtime {
2020namespace deserialization {
2121
22+ using executorch::aten::ScalarType;
23+ using executorch::runtime::TensorLayout;
2224// Provides access to private Program methods.
2325class TensorParser final {
2426 public:
@@ -113,7 +115,8 @@ ET_NODISCARD Result<void*> getTensorDataPtr(
113115 const executorch_flatbuffer::Tensor* s_tensor,
114116 const Program* program,
115117 size_t nbytes,
116- HierarchicalAllocator* allocator) {
118+ HierarchicalAllocator* allocator,
119+ const NamedDataMap* named_data_map) {
117120 auto data_buffer_idx = s_tensor->data_buffer_idx ();
118121 const executorch_flatbuffer::AllocationDetails* allocation_info =
119122 s_tensor->allocation_info ();
@@ -132,8 +135,76 @@ ET_NODISCARD Result<void*> getTensorDataPtr(
132135 }
133136 return planned_ptr;
134137
135- // Constant
136- } else if (data_buffer_idx > 0 && allocation_info == nullptr ) {
138+ }
139+ // Constant, stored externally.
140+ else if (
141+ allocation_info == nullptr && s_tensor->extra_tensor_info () != nullptr &&
142+ s_tensor->extra_tensor_info ()->location () ==
143+ executorch_flatbuffer::TensorDataLocation::EXTERNAL) {
144+ // Check that fqn is not null.
145+ ET_CHECK_OR_RETURN_ERROR (
146+ s_tensor->extra_tensor_info ()->fully_qualified_name () != nullptr ,
147+ InvalidExternalData,
148+ " Fully qualified name of external tensor is null" );
149+ // Look up tensor in named data map.
150+ Result<const TensorLayout> tensor_layout_res = named_data_map->get_metadata (
151+ s_tensor->extra_tensor_info ()->fully_qualified_name ()->c_str ());
152+ if (!tensor_layout_res.ok ()) {
153+ return tensor_layout_res.error ();
154+ }
155+ const TensorLayout& tensor_layout = tensor_layout_res.get ();
156+
157+ // Compatibility checking.
158+ ET_CHECK_OR_RETURN_ERROR (
159+ static_cast <ScalarType>(s_tensor->scalar_type ()) ==
160+ tensor_layout.scalar_type (),
161+ InvalidExternalData,
162+ " Scalar type mismatch. Expected %hhd, got %hhd." ,
163+ static_cast <int8_t >(s_tensor->scalar_type ()),
164+ static_cast <int8_t >(tensor_layout.scalar_type ()));
165+ ET_CHECK_OR_RETURN_ERROR (
166+ nbytes == tensor_layout.nbytes (),
167+ InvalidExternalData,
168+ " Nbytes mismatch. Expected %zu, got %zu." ,
169+ nbytes,
170+ tensor_layout.nbytes ());
171+ int dim = s_tensor->sizes ()->size ();
172+ ET_CHECK_OR_RETURN_ERROR (
173+ dim == tensor_layout.sizes ().size (),
174+ InvalidExternalData,
175+ " Dim mismatch. Expected %d, got %zu." ,
176+ dim,
177+ tensor_layout.sizes ().size ());
178+ for (int i = 0 ; i < dim; i++) {
179+ ET_CHECK_OR_RETURN_ERROR (
180+ s_tensor->sizes ()->Get (i) == tensor_layout.sizes ()[i],
181+ InvalidExternalData,
182+ " Sizes mismatch. Expected %d, got %d for size at index %d." ,
183+ s_tensor->sizes ()->Get (i),
184+ tensor_layout.sizes ()[i],
185+ i);
186+ ET_CHECK_OR_RETURN_ERROR (
187+ s_tensor->dim_order ()->Get (i) == tensor_layout.dim_order ()[i],
188+ InvalidExternalData,
189+ " Dim order mismatch. Expected %d, got %d for dim at index %d." ,
190+ s_tensor->dim_order ()->Get (i),
191+ tensor_layout.dim_order ()[i],
192+ i);
193+ }
194+
195+ Result<FreeableBuffer> data_res = named_data_map->get_data (
196+ s_tensor->extra_tensor_info ()->fully_qualified_name ()->c_str ());
197+ if (!data_res.ok ()) {
198+ return data_res.error ();
199+ }
200+ // The const_cast is 'ok' here because program and runtime should guarantee
201+ // that this data is never modified. Temporary until we introduce the
202+ // `get_and_persist_data` API from TODO(T214294528).
203+ return const_cast <void *>(static_cast <const void *>(data_res.get ().data ()));
204+ }
205+
206+ // Constant, stored in PTE file.
207+ else if (data_buffer_idx > 0 && allocation_info == nullptr ) {
137208 auto const_data =
138209 program->get_constant_buffer_data (data_buffer_idx, nbytes);
139210 if (!const_data.ok ()) {
0 commit comments