Skip to content

Commit 89dc36c

Browse files
pytorchbotlucylq
andauthored
[executorch][runtime] Add NamedDataMap to method load (#8383)
Pull Request resolved: #8200 Add NamedDataMap as an arg to: - Method - load_method - parseTensor Use NamedDataMap to resolve external tensors in parseTensor. Test that the PTE + PTD file run well inside method_test. TODO: additional test cases. also, tests for mutable case with load_data_into when that is landed, see D69148652. Land after: #8349, which adds CMake support for FlatTensor. Note: dependency on D66580784, which fixes some failing RL tests exposed by this diff from inclusion of portable and aten headers. https://www.internalfb.com/code/fbsource/[2b74908ed03c34fbfd53fb57575eba0964fe0136][history]/arvr/projects/depthsensing/products/depthmanager/depth/stereo/MlStereoDisparityModelExecutorchBackend.h?lines=13-15 ghstack-source-id: 265828564 @exported-using-ghexport Differential Revision: [D67127327](https://our.internmc.facebook.com/intern/diff/D67127327/) Co-authored-by: lucylq <[email protected]>
1 parent 1308d4d commit 89dc36c

14 files changed

+203
-24
lines changed

extension/flat_tensor/test/targets.bzl

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ def define_common_targets(is_fbcode=False):
3535
# The tests use this var to find the program file to load. This uses
3636
# an fbcode target path because the authoring/export tools
3737
# intentionally don't work in xplat (since they're host-only tools).
38-
"ET_MODULE_LINEAR_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_programs_with_data_separated[ModuleLinear.pte])",
39-
"ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_programs_with_data_separated[ModuleLinear.ptd])",
38+
"ET_MODULE_LINEAR_PROGRAM_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.pte])",
39+
"ET_MODULE_LINEAR_DATA_PATH": "$(location fbcode//executorch/test/models:exported_program_and_data[ModuleLinear.ptd])",
4040
}
4141

4242
runtime.cxx_test(

runtime/executor/method.cpp

+11-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <executorch/runtime/backend/interface.h>
1717
#include <executorch/runtime/core/event_tracer_hooks.h>
1818
#include <executorch/runtime/core/exec_aten/util/tensor_util.h>
19+
#include <executorch/runtime/core/named_data_map.h>
1920
#include <executorch/runtime/core/span.h>
2021
#include <executorch/runtime/executor/memory_manager.h>
2122
#include <executorch/runtime/executor/platform_memory_allocator.h>
@@ -288,7 +289,7 @@ Result<bool> parse_cond_value(const EValue& cond_value) {
288289

289290
} // namespace
290291

291-
Error Method::parse_values() {
292+
Error Method::parse_values(const NamedDataMap* named_data_map) {
292293
auto flatbuffer_values = serialization_plan_->values();
293294
ET_CHECK_OR_RETURN_ERROR(
294295
flatbuffer_values != nullptr, InvalidProgram, "Missing values");
@@ -414,7 +415,8 @@ Error Method::parse_values() {
414415
auto t = deserialization::parseTensor(
415416
program_,
416417
memory_manager_,
417-
static_cast<const executorch_flatbuffer::Tensor*>(val));
418+
static_cast<const executorch_flatbuffer::Tensor*>(val),
419+
named_data_map);
418420
if (!t.ok()) {
419421
ET_LOG(
420422
Error,
@@ -607,7 +609,8 @@ Result<Method> Method::load(
607609
executorch_flatbuffer::ExecutionPlan* s_plan,
608610
const Program* program,
609611
MemoryManager* memory_manager,
610-
EventTracer* event_tracer) {
612+
EventTracer* event_tracer,
613+
const NamedDataMap* named_data_map) {
611614
MemoryAllocator* temp_allocator = memory_manager->temp_allocator();
612615
if (temp_allocator == nullptr) {
613616
PlatformMemoryAllocator* platform_allocator =
@@ -621,7 +624,7 @@ Result<Method> Method::load(
621624
}
622625
Method method(program, memory_manager, event_tracer, temp_allocator);
623626

624-
Error err = method.init(s_plan);
627+
Error err = method.init(s_plan, named_data_map);
625628
if (err != Error::Ok) {
626629
return err;
627630
} else {
@@ -630,7 +633,9 @@ Result<Method> Method::load(
630633
}
631634
}
632635

633-
Error Method::init(executorch_flatbuffer::ExecutionPlan* s_plan) {
636+
Error Method::init(
637+
executorch_flatbuffer::ExecutionPlan* s_plan,
638+
const NamedDataMap* named_data_map) {
634639
EXECUTORCH_SCOPE_PROF("Method::init");
635640
internal::EventTracerProfileMethodScope event_tracer_profile_scope =
636641
internal::EventTracerProfileMethodScope(event_tracer_, "Method::init");
@@ -647,7 +652,7 @@ Error Method::init(executorch_flatbuffer::ExecutionPlan* s_plan) {
647652

648653
{
649654
// Parse the elements of the values_ array.
650-
Error err = parse_values();
655+
Error err = parse_values(named_data_map);
651656
if (err != Error::Ok) {
652657
return err;
653658
}

runtime/executor/method.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <executorch/runtime/core/evalue.h>
1515
#include <executorch/runtime/core/event_tracer.h>
1616
#include <executorch/runtime/core/exec_aten/exec_aten.h>
17+
#include <executorch/runtime/core/named_data_map.h>
1718
#include <executorch/runtime/core/span.h>
1819
#include <executorch/runtime/executor/memory_manager.h>
1920
#include <executorch/runtime/executor/method_meta.h>
@@ -294,14 +295,17 @@ class Method final {
294295
executorch_flatbuffer::ExecutionPlan* s_plan,
295296
const Program* program,
296297
MemoryManager* memory_manager,
297-
EventTracer* event_tracer);
298+
EventTracer* event_tracer,
299+
const NamedDataMap* named_data_map);
298300

299301
/**
300302
* Initialize the method from its serialized representation.
301303
*
302304
* @returns Error::Ok on success, non-Ok on failure.
303305
*/
304-
ET_NODISCARD Error init(executorch_flatbuffer::ExecutionPlan* s_plan);
306+
ET_NODISCARD Error init(
307+
executorch_flatbuffer::ExecutionPlan* s_plan,
308+
const NamedDataMap* named_data_map);
305309

306310
/// Returns true if the Method was successfully initialized.
307311
inline bool initialized() const {
@@ -339,7 +343,7 @@ class Method final {
339343
* the number of successfully-initialized entries so that ~Method doesn't try
340344
* to clean up uninitialized entries.
341345
*/
342-
ET_NODISCARD Error parse_values();
346+
ET_NODISCARD Error parse_values(const NamedDataMap* named_data_map);
343347

344348
ET_NODISCARD Error resolve_operator(
345349
int32_t op_index,

runtime/executor/program.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ Result<const char*> Program::get_method_name(size_t plan_index) const {
240240
Result<Method> Program::load_method(
241241
const char* method_name,
242242
MemoryManager* memory_manager,
243-
EventTracer* event_tracer) const {
243+
EventTracer* event_tracer,
244+
const NamedDataMap* named_data_map) const {
244245
EXECUTORCH_SCOPE_PROF("Program::load_method");
245246
internal::event_tracer_create_event_block(event_tracer, "Default");
246247
internal::EventTracerProfileMethodScope event_tracer_scope =
@@ -257,7 +258,8 @@ Result<Method> Program::load_method(
257258
if (!plan.ok()) {
258259
return plan.error();
259260
}
260-
return Method::load(plan.get(), this, memory_manager, event_tracer);
261+
return Method::load(
262+
plan.get(), this, memory_manager, event_tracer, named_data_map);
261263
}
262264

263265
Result<MethodMeta> Program::method_meta(const char* method_name) const {

runtime/executor/program.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,16 @@ class Program final {
129129
* execution of the loaded method. If `memory_manager.temp_allocator()` is
130130
* null, the runtime will allocate temp memory using `et_pal_allocate()`.
131131
* @param[in] event_tracer The event tracer to use for this method run.
132+
* @param[in] named_data_map An optional map of {name, blob} used to resolve
133+
* data that is external to the PTE, if any.
132134
*
133135
* @returns The loaded method on success, or an error on failure.
134136
*/
135137
Result<Method> load_method(
136138
const char* method_name,
137139
MemoryManager* memory_manager,
138-
EventTracer* event_tracer = nullptr) const;
140+
EventTracer* event_tracer = nullptr,
141+
const NamedDataMap* named_data_map = nullptr) const;
139142

140143
/**
141144
* Gathers metadata for the named method.

runtime/executor/targets.bzl

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def define_common_targets():
7979
":memory_manager",
8080
"//executorch/runtime/backend:interface",
8181
"//executorch/runtime/core:core",
82+
"//executorch/runtime/core:named_data_map",
8283
"//executorch/runtime/core:evalue" + aten_suffix,
8384
"//executorch/runtime/core:event_tracer" + aten_suffix,
8485
"//executorch/runtime/core/exec_aten:lib" + aten_suffix,

runtime/executor/tensor_parser.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
*/
88

99
#pragma once
10+
// Disable -Wdeprecated-declarations, as some builds use 'Werror'.
11+
#pragma GCC diagnostic push
12+
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1013

1114
#include <executorch/runtime/core/evalue.h>
1215
#include <executorch/runtime/core/exec_aten/exec_aten.h>
@@ -21,7 +24,8 @@ namespace deserialization {
2124
ET_NODISCARD Result<executorch::aten::Tensor> parseTensor(
2225
const Program* program,
2326
MemoryManager* memory_manager,
24-
const executorch_flatbuffer::Tensor* s_tensor);
27+
const executorch_flatbuffer::Tensor* s_tensor,
28+
const NamedDataMap* named_data_map = nullptr);
2529

2630
ET_NODISCARD Result<BoxedEvalueList<executorch::aten::Tensor>> parseTensorList(
2731
const flatbuffers::Vector<int32_t>* tensor_indices,
@@ -100,6 +104,8 @@ parseListOptionalType(
100104
* @param[in] program The Program to use for constant buffer data.
101105
* @param[in] nbytes The amount of memory to get from the allocator.
102106
* @param[in] allocator The source of memory for non-constant tensors.
107+
* @param[in] named_data_map An optional map of {name, blob} used to resolve
108+
* data that is external to the PTE, if any.
103109
*
104110
* @returns On success, the data pointer to use for the tensor. On failure, a
105111
* non-Ok Error.
@@ -108,7 +114,8 @@ ET_NODISCARD Result<void*> getTensorDataPtr(
108114
const executorch_flatbuffer::Tensor* s_tensor,
109115
const Program* program,
110116
size_t nbytes,
111-
HierarchicalAllocator* allocator);
117+
HierarchicalAllocator* allocator,
118+
const NamedDataMap* named_data_map = nullptr);
112119

113120
} // namespace deserialization
114121
} // namespace runtime
@@ -126,3 +133,4 @@ using ::executorch::runtime::deserialization::parseTensorList;
126133
} // namespace deserialization
127134
} // namespace executor
128135
} // namespace torch
136+
#pragma GCC diagnostic pop

runtime/executor/tensor_parser_aten.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <executorch/runtime/core/exec_aten/util/dim_order_util.h>
1212
#include <executorch/runtime/core/exec_aten/util/scalar_type_util.h>
13+
#include <executorch/runtime/core/named_data_map.h>
1314
#include <executorch/runtime/executor/memory_manager.h>
1415
#include <executorch/runtime/executor/program.h>
1516
#include <executorch/runtime/platform/profiler.h>
@@ -31,7 +32,8 @@ void deleteNothing(void*) {}
3132
Result<at::Tensor> parseTensor(
3233
const Program* program,
3334
MemoryManager* memory_manager,
34-
const executorch_flatbuffer::Tensor* s_tensor) {
35+
const executorch_flatbuffer::Tensor* s_tensor,
36+
const NamedDataMap* named_data_map) {
3537
EXECUTORCH_SCOPE_PROF("TensorParser::parseTensor");
3638

3739
ET_CHECK_OR_RETURN_ERROR(
@@ -102,7 +104,11 @@ Result<at::Tensor> parseTensor(
102104
} else {
103105
// Now that we know how big the tensor is, find and assign its memory.
104106
Result<void*> data_ptr = getTensorDataPtr(
105-
s_tensor, program, tensor.nbytes(), memory_manager->planned_memory());
107+
s_tensor,
108+
program,
109+
tensor.nbytes(),
110+
memory_manager->planned_memory(),
111+
named_data_map);
106112
if (!data_ptr.ok()) {
107113
ET_LOG(
108114
Error,

runtime/executor/tensor_parser_exec_aten.cpp

+100-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ namespace executorch {
1919
namespace runtime {
2020
namespace deserialization {
2121

22+
using executorch::aten::ScalarType;
23+
using executorch::runtime::TensorLayout;
2224
// Provides access to private Program methods.
2325
class 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();
@@ -131,9 +134,103 @@ ET_NODISCARD Result<void*> getTensorDataPtr(
131134
return err;
132135
}
133136
return planned_ptr;
137+
}
138+
139+
// External tensors.
140+
else if (
141+
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+
// Constant value.
196+
if (allocation_info == nullptr) {
197+
Result<FreeableBuffer> data_res = named_data_map->get_data(
198+
s_tensor->extra_tensor_info()->fully_qualified_name()->c_str());
199+
if (!data_res.ok()) {
200+
return data_res.error();
201+
}
202+
// The const_cast is 'ok' here because program and runtime should
203+
// guarantee that this data is never modified. Temporary until runtime
204+
// takes ownership of FreeableBuffers in TODO(T214294528).
205+
return const_cast<void*>(data_res.get().data());
206+
}
207+
208+
// Mutable value.
209+
else {
210+
// Call load_into.
211+
auto planned_ptr = getMemPlannedPtr(allocation_info, nbytes, allocator);
212+
if (!planned_ptr.ok()) {
213+
return planned_ptr.error();
214+
}
215+
auto size = named_data_map->load_data_into(
216+
s_tensor->extra_tensor_info()->fully_qualified_name()->c_str(),
217+
planned_ptr.get(),
218+
nbytes);
219+
if (size.error() != Error::Ok) {
220+
return size.error();
221+
}
222+
ET_CHECK_OR_RETURN_ERROR(
223+
size.get() == nbytes,
224+
InvalidExternalData,
225+
"Expected to load %zu bytes, actually loaded %u bytes",
226+
nbytes,
227+
static_cast<unsigned int>(size.get()));
228+
return planned_ptr;
229+
}
230+
}
134231

135-
// Constant
136-
} else if (data_buffer_idx > 0 && allocation_info == nullptr) {
232+
// Constant, stored in PTE file.
233+
else if (data_buffer_idx > 0 && allocation_info == nullptr) {
137234
auto const_data =
138235
program->get_constant_buffer_data(data_buffer_idx, nbytes);
139236
if (!const_data.ok()) {

runtime/executor/tensor_parser_portable.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <executorch/runtime/core/exec_aten/exec_aten.h>
1212
#include <executorch/runtime/core/exec_aten/util/dim_order_util.h>
1313
#include <executorch/runtime/core/exec_aten/util/scalar_type_util.h>
14+
#include <executorch/runtime/core/named_data_map.h>
1415
#include <executorch/runtime/executor/memory_manager.h>
1516
#include <executorch/runtime/executor/program.h>
1617
#include <executorch/runtime/platform/profiler.h>
@@ -27,7 +28,8 @@ using torch::executor::TensorImpl;
2728
Result<Tensor> parseTensor(
2829
const Program* program,
2930
MemoryManager* memory_manager,
30-
const executorch_flatbuffer::Tensor* s_tensor) {
31+
const executorch_flatbuffer::Tensor* s_tensor,
32+
const NamedDataMap* named_data_map) {
3133
EXECUTORCH_SCOPE_PROF("TensorParser::parseTensor");
3234
auto method_allocator = memory_manager->method_allocator();
3335

@@ -146,7 +148,8 @@ Result<Tensor> parseTensor(
146148
s_tensor,
147149
program,
148150
tensor_impl->nbytes(),
149-
memory_manager->planned_memory());
151+
memory_manager->planned_memory(),
152+
named_data_map);
150153
if (!data_ptr.ok()) {
151154
ET_LOG(
152155
Error,

0 commit comments

Comments
 (0)