Skip to content

Commit 062fcb9

Browse files
committed
[executorch][runtime] Introduce CoreDataMap for weight sharing
CoreDataMap is the NamedDataMap that will live in the runtime. It is used to give delegates access to opaque named data stored in the PTE file. Open to alternative naming suggestions, maybe 'PTEDataMap' or 'ProgramDataMap'? **Usage** The CoreDataMap is owned by the program, and instantiated at program load time if named_data exists in the PTE file. We introduce usage of 'std::optional' here. I think we can also use executorch::aten::optional to avoid adding standard lib ? When initializing delegates, the CoreDataMap is given to delegate_init. Delegates can retrieve opaque delegate data by key using 'get_data'. **Testing** This test uses the C++ flatbuffer API to build a fake program containing named data. Creates a temp file with sample data that the data loader can wrap around. TODO: e2e test once delegate aot is ready and we can generate a file with named data. **Note** As the CoreDataMap wraps around flatbuffer constructs, the Program must outlive the CoreDataMap. CoreDataMap does not implement - get_metadata; currently, all data stored is opaque. Later, we can implement get_metadata if a backend stores plain tensor data. - load_into; this is mostly used for the training case, and isn't used by delegates, at least not at the moment. Differential Revision: [D70213646](https://our.internmc.facebook.com/intern/diff/D70213646/) [ghstack-poisoned]
1 parent 657228e commit 062fcb9

File tree

8 files changed

+478
-4
lines changed

8 files changed

+478
-4
lines changed

extension/testing_util/targets.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ def define_common_targets():
1616
"//executorch/extension/testing_util/test/...",
1717
"//executorch/extension/fb/ptez/decompression_methods/test/...",
1818
"//executorch/extension/fb/ptez/test/...",
19+
"//executorch/runtime/executor/test/...",
1920
],
2021
)

runtime/executor/core_data_map.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#include "executorch/runtime/executor/core_data_map.h"
10+
#include <executorch/schema/program_generated.h>
11+
12+
namespace executorch {
13+
namespace runtime {
14+
15+
/* static */ executorch::runtime::Result<CoreDataMap> CoreDataMap::load(
16+
executorch::runtime::DataLoader* loader,
17+
size_t segment_base_offset,
18+
const flatbuffers::Vector<
19+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
20+
const flatbuffers::Vector<
21+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments) {
22+
ET_CHECK_OR_RETURN_ERROR(
23+
loader != nullptr && named_data != nullptr && segments != nullptr,
24+
InvalidArgument,
25+
"CoreDataMap loader, named_data or segments is null; most likely the program does not have any named_data segments");
26+
return CoreDataMap(loader, segment_base_offset, named_data, segments);
27+
}
28+
29+
ET_NODISCARD
30+
executorch::runtime::Result<executorch::runtime::FreeableBuffer>
31+
CoreDataMap::get_data(const char* key) const {
32+
for (size_t i = 0; i < named_data_->size(); i++) {
33+
ET_CHECK_OR_RETURN_ERROR(
34+
named_data_->Get(i) != nullptr && named_data_->Get(i)->key() != nullptr,
35+
InvalidArgument,
36+
"NamedData at index %zu is null",
37+
i);
38+
if (strcmp(named_data_->Get(i)->key()->c_str(), key) == 0) {
39+
// Get the segment index.
40+
size_t segment_index = named_data_->Get(i)->segment_index();
41+
42+
// Get the segment offset and size.
43+
ET_CHECK_OR_RETURN_ERROR(
44+
segment_index < segments_->size(),
45+
InvalidArgument,
46+
"Segment index %zu is out of range for segments size %u",
47+
segment_index,
48+
segments_->size());
49+
size_t segment_offset = segments_->Get(segment_index)->offset();
50+
size_t segment_size = segments_->Get(segment_index)->size();
51+
52+
return loader_->load(
53+
/*offset=*/segment_base_offset_ + segment_offset,
54+
segment_size,
55+
DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::External));
56+
}
57+
}
58+
return Error::NotFound;
59+
}
60+
61+
ET_NODISCARD executorch::runtime::Result<size_t> CoreDataMap::get_num_keys()
62+
const {
63+
return named_data_->size();
64+
}
65+
66+
ET_NODISCARD executorch::runtime::Result<const char*> CoreDataMap::get_key(
67+
size_t index) const {
68+
ET_CHECK_OR_RETURN_ERROR(
69+
index < named_data_->size(),
70+
InvalidArgument,
71+
"Index out of range: named_data size is %u, received index %zu",
72+
named_data_->size(),
73+
index);
74+
75+
ET_CHECK_OR_RETURN_ERROR(
76+
named_data_->Get(index) != nullptr &&
77+
named_data_->Get(index)->key() != nullptr,
78+
InvalidArgument,
79+
"NamedData at index %zu is null",
80+
index);
81+
return named_data_->Get(index)->key()->c_str();
82+
}
83+
84+
} // namespace runtime
85+
} // namespace executorch

runtime/executor/core_data_map.h

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
11+
#include <executorch/runtime/core/data_loader.h>
12+
#include <executorch/runtime/core/named_data_map.h>
13+
14+
// Forward declare flatbuffer types. This is a public header and must not
15+
// include the generated flatbuffer header.
16+
namespace flatbuffers {
17+
template <typename T>
18+
class Vector;
19+
template <typename T>
20+
struct Offset;
21+
} // namespace flatbuffers
22+
23+
namespace executorch_flatbuffer {
24+
struct NamedData;
25+
struct DataSegment;
26+
} // namespace executorch_flatbuffer
27+
28+
namespace executorch {
29+
namespace runtime {
30+
31+
/**
32+
* A NamedDataMap implementation for Flatbuffer-serialized named data
33+
* originating from a PTE file.
34+
*/
35+
class CoreDataMap final : public executorch::runtime::NamedDataMap {
36+
public:
37+
/**
38+
* Creates a new DataMap that wraps named_data from the PTE file.
39+
*
40+
* @param[in] loader The DataLoader that accesses the PTE file.
41+
* Note: the loader must outlive the CoreDataMap instance.
42+
* @param[in] segment_base_offset The offset to the first segment in the PTE
43+
* file, in bytes.
44+
* @param[in] named_data The named_data from the PTE file. Note: the pointer
45+
* passed here must outlive the CoreDataMap instance.
46+
* @param[in] segments The segments from the PTE file. Note: the pointer
47+
* passed here must outlive the CoreDataMap instance.
48+
*/
49+
static executorch::runtime::Result<CoreDataMap> load(
50+
executorch::runtime::DataLoader* loader,
51+
size_t segment_base_offset,
52+
const flatbuffers::Vector<
53+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
54+
const flatbuffers::Vector<
55+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments);
56+
57+
/**
58+
* The CoreDataMap currently only handles opaque data that does not contain
59+
* tensor-specific metadata.
60+
*/
61+
ET_NODISCARD
62+
executorch::runtime::Result<const executorch::runtime::TensorLayout>
63+
get_metadata(ET_UNUSED const char* key) const override {
64+
return Error::NotImplemented;
65+
}
66+
67+
/**
68+
* Retrieve read-only data for the specified key.
69+
*
70+
* @param[in] key The name of the blob to get data on.
71+
*
72+
* @return error if the key is not present or data cannot be loaded.
73+
*/
74+
ET_NODISCARD
75+
executorch::runtime::Result<executorch::runtime::FreeableBuffer> get_data(
76+
const char* key) const override;
77+
78+
/**
79+
* The CoreDataMap currently does not implement load_into.
80+
*/
81+
ET_NODISCARD executorch::runtime::Error load_data_into(
82+
ET_UNUSED const char* key,
83+
ET_UNUSED void* buffer,
84+
ET_UNUSED size_t size) const override {
85+
return Error::NotImplemented;
86+
}
87+
88+
/**
89+
* @returns The number of keys in the map.
90+
*/
91+
ET_NODISCARD executorch::runtime::Result<size_t> get_num_keys()
92+
const override;
93+
94+
/**
95+
* @returns The key at the specified index, error if index out of bounds.
96+
*/
97+
ET_NODISCARD executorch::runtime::Result<const char*> get_key(
98+
size_t index) const override;
99+
100+
// Moveable, to be compatible with Result.
101+
CoreDataMap(CoreDataMap&&) noexcept = default;
102+
~CoreDataMap() override = default;
103+
104+
private:
105+
CoreDataMap(
106+
executorch::runtime::DataLoader* loader,
107+
size_t segment_base_offset,
108+
const flatbuffers::Vector<
109+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
110+
const flatbuffers::Vector<
111+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments)
112+
: loader_(loader),
113+
segment_base_offset_(segment_base_offset),
114+
named_data_(named_data),
115+
segments_(segments) {}
116+
117+
// Not copyable or assignable.
118+
CoreDataMap(const CoreDataMap& rhs) = delete;
119+
CoreDataMap& operator=(CoreDataMap&& rhs) noexcept = delete;
120+
CoreDataMap& operator=(const CoreDataMap& rhs) = delete;
121+
122+
// Data loader, used to load segment data.
123+
executorch::runtime::DataLoader* loader_;
124+
125+
// Segment base offset.
126+
size_t segment_base_offset_;
127+
128+
// Named data, containing name and segment index.
129+
const flatbuffers::Vector<
130+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data_;
131+
132+
// Segments, to retrieve offset and size for the loader.
133+
const flatbuffers::Vector<
134+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments_;
135+
};
136+
137+
} // namespace runtime
138+
} // namespace executorch

runtime/executor/program.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,21 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
150150
const executorch_flatbuffer::Program* flatbuffer_program =
151151
executorch_flatbuffer::GetProgram(program_data->data());
152152

153+
// Instantiate CoreDataMap if named_data is present.
154+
const auto named_data = flatbuffer_program->named_data();
155+
std::optional<CoreDataMap> core_data_map = std::nullopt;
156+
if (named_data != nullptr) {
157+
Result<CoreDataMap> core_data_map_result = CoreDataMap::load(
158+
loader,
159+
segment_base_offset,
160+
named_data,
161+
flatbuffer_program->segments());
162+
if (!core_data_map_result.ok()) {
163+
return core_data_map_result.error();
164+
}
165+
core_data_map.emplace(std::move(core_data_map_result.get()));
166+
}
167+
153168
// Constant data may live inside the flatbuffer data (constant_buffer) or in a
154169
// separate segment (constant_segment). It should not be in both.
155170
// Check constant_segment->offsets()->size() > 1, as the offsets list will
@@ -199,7 +214,8 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
199214
segment_base_offset,
200215
std::move(program_data.get()),
201216
flatbuffer_program,
202-
std::move(constant_segment_data.get()));
217+
std::move(constant_segment_data.get()),
218+
std::move(core_data_map));
203219
} else {
204220
// The constant data is stored inside the flatbuffer, so this program does
205221
// not contain a separate segment for it.
@@ -208,7 +224,8 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
208224
segment_base_offset,
209225
std::move(program_data.get()),
210226
flatbuffer_program,
211-
/*constant_segment_data=*/FreeableBuffer{});
227+
/*constant_segment_data=*/FreeableBuffer{},
228+
std::move(core_data_map));
212229
}
213230
}
214231

runtime/executor/program.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
#include <cinttypes>
1515
#include <cstdint>
16+
#include <optional>
1617

1718
#include <executorch/runtime/core/data_loader.h>
1819
#include <executorch/runtime/core/error.h>
1920
#include <executorch/runtime/core/event_tracer.h>
2021
#include <executorch/runtime/core/freeable_buffer.h>
2122
#include <executorch/runtime/core/result.h>
23+
#include <executorch/runtime/executor/core_data_map.h>
2224
#include <executorch/runtime/executor/memory_manager.h>
2325
#include <executorch/runtime/executor/method.h>
2426
#include <executorch/runtime/executor/method_meta.h>
@@ -266,13 +268,15 @@ class Program final {
266268
size_t segment_base_offset,
267269
FreeableBuffer&& program_data,
268270
const executorch_flatbuffer::Program* internal_program,
269-
FreeableBuffer&& constant_segment_data)
271+
FreeableBuffer&& constant_segment_data,
272+
std::optional<CoreDataMap>&& core_data_map)
270273
: program_data_(std::move(program_data)),
271274
// Don't need the loader if there are no segments.
272275
loader_(segment_base_offset > 0 ? loader : nullptr),
273276
internal_program_(internal_program),
274277
segment_base_offset_(segment_base_offset),
275-
constant_segment_data_(std::move(constant_segment_data)) {}
278+
constant_segment_data_(std::move(constant_segment_data)),
279+
core_data_map_(std::move(core_data_map)) {}
276280

277281
// Not copyable or assignable.
278282
Program(const Program& rhs) = delete;
@@ -295,6 +299,9 @@ class Program final {
295299

296300
/// Constant segment data.
297301
FreeableBuffer constant_segment_data_;
302+
303+
/// NamedDataMap holding named data from the program.
304+
std::optional<CoreDataMap> core_data_map_;
298305
};
299306

300307
} // namespace runtime

runtime/executor/targets.bzl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@ def define_common_targets():
4242
],
4343
)
4444

45+
runtime.cxx_library(
46+
name = "core_data_map",
47+
srcs = [
48+
"core_data_map.cpp",
49+
],
50+
exported_headers = [
51+
"core_data_map.h",
52+
],
53+
visibility = [
54+
"//executorch/runtime/executor/...",
55+
"@EXECUTORCH_CLIENTS",
56+
],
57+
deps = [
58+
"//executorch/runtime/core:core",
59+
"//executorch/runtime/core:named_data_map",
60+
"//executorch/schema:program",
61+
],
62+
)
63+
4564
for aten_mode in get_aten_mode_options():
4665
aten_suffix = "_aten" if aten_mode else ""
4766
runtime.cxx_library(
@@ -59,6 +78,7 @@ def define_common_targets():
5978
runtime.cxx_library(
6079
name = "program_no_prim_ops" + aten_suffix,
6180
srcs = [
81+
"core_data_map.cpp",
6282
"method.cpp",
6383
"method_meta.cpp",
6484
"program.cpp",
@@ -69,6 +89,7 @@ def define_common_targets():
6989
"platform_memory_allocator.h",
7090
],
7191
exported_headers = [
92+
"core_data_map.h",
7293
"method.h",
7394
"method_meta.h",
7495
"program.h",

0 commit comments

Comments
 (0)