Skip to content

Commit ace940f

Browse files
committed
[executorch][runtime] Introduce PteDataMap for weight sharing
PteDataMap 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 PteDataMap 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 PteDataMap is given to delegate_init. Delegates can retrieve opaque delegate data by key using 'get_data'. This gives them a FreeableBuffer that they can free later. **Testing** This test uses the C++ flatbuffer API to build a fake program containing named data. We also 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 PteDataMap wraps around flatbuffer constructs, the Program must outlive the PteDataMap. PteDataMap 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-source-id: 269379135 Pull Request resolved: #8887
1 parent 542480c commit ace940f

File tree

8 files changed

+562
-4
lines changed

8 files changed

+562
-4
lines changed

extension/testing_util/targets.bzl

+1
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/program.cpp

+20-2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,22 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
150150
const executorch_flatbuffer::Program* flatbuffer_program =
151151
executorch_flatbuffer::GetProgram(program_data->data());
152152

153+
// Instantiate PteDataMap if named_data is present.
154+
const auto named_data = flatbuffer_program->named_data();
155+
std::optional<internal::PteDataMap> pte_data_map = std::nullopt;
156+
if (named_data != nullptr) {
157+
Result<internal::PteDataMap> pte_data_map_result =
158+
internal::PteDataMap::create(
159+
loader,
160+
segment_base_offset,
161+
named_data,
162+
flatbuffer_program->segments());
163+
if (!pte_data_map_result.ok()) {
164+
return pte_data_map_result.error();
165+
}
166+
pte_data_map.emplace(std::move(pte_data_map_result.get()));
167+
}
168+
153169
// Constant data may live inside the flatbuffer data (constant_buffer) or in a
154170
// separate segment (constant_segment). It should not be in both.
155171
// Check constant_segment->offsets()->size() > 1, as the offsets list will
@@ -199,7 +215,8 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
199215
segment_base_offset,
200216
std::move(program_data.get()),
201217
flatbuffer_program,
202-
std::move(constant_segment_data.get()));
218+
std::move(constant_segment_data.get()),
219+
std::move(pte_data_map));
203220
} else {
204221
// The constant data is stored inside the flatbuffer, so this program does
205222
// not contain a separate segment for it.
@@ -208,7 +225,8 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
208225
segment_base_offset,
209226
std::move(program_data.get()),
210227
flatbuffer_program,
211-
/*constant_segment_data=*/FreeableBuffer{});
228+
/*constant_segment_data=*/FreeableBuffer{},
229+
std::move(pte_data_map));
212230
}
213231
}
214232

runtime/executor/program.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
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>
@@ -22,6 +23,7 @@
2223
#include <executorch/runtime/executor/memory_manager.h>
2324
#include <executorch/runtime/executor/method.h>
2425
#include <executorch/runtime/executor/method_meta.h>
26+
#include <executorch/runtime/executor/pte_data_map.h>
2527
#include <executorch/runtime/platform/compiler.h>
2628

2729
// Forward declare flatbuffer types. This is a public header and must not
@@ -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<internal::PteDataMap>&& 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<internal::PteDataMap> core_data_map_;
298305
};
299306

300307
} // namespace runtime

runtime/executor/pte_data_map.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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/pte_data_map.h>
10+
#include <executorch/schema/program_generated.h>
11+
12+
namespace executorch {
13+
namespace runtime {
14+
namespace internal {
15+
16+
/* static */ executorch::runtime::Result<PteDataMap> PteDataMap::create(
17+
executorch::runtime::DataLoader* loader,
18+
size_t segment_base_offset,
19+
const flatbuffers::Vector<
20+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
21+
const flatbuffers::Vector<
22+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments) {
23+
ET_CHECK_OR_RETURN_ERROR(
24+
loader != nullptr && named_data != nullptr && segments != nullptr,
25+
InvalidArgument,
26+
"PteDataMap loader, named_data or segments is null; most likely the program does not have any named_data segments");
27+
return PteDataMap(loader, segment_base_offset, named_data, segments);
28+
}
29+
30+
ET_NODISCARD
31+
executorch::runtime::Result<executorch::runtime::FreeableBuffer>
32+
PteDataMap::get_data(const char* key) const {
33+
for (size_t i = 0; i < named_data_->size(); i++) {
34+
ET_CHECK_OR_RETURN_ERROR(
35+
named_data_->Get(i) != nullptr && named_data_->Get(i)->key() != nullptr,
36+
InvalidArgument,
37+
"Searching for key %s: NamedData at index %zu is null",
38+
key,
39+
i);
40+
if (strcmp(named_data_->Get(i)->key()->c_str(), key) == 0) {
41+
// Get the segment index.
42+
size_t segment_index = named_data_->Get(i)->segment_index();
43+
44+
// Get the segment offset and size.
45+
ET_CHECK_OR_RETURN_ERROR(
46+
segment_index < segments_->size(),
47+
InvalidArgument,
48+
"Segment index %zu for key %s is out of range for segments size %u",
49+
segment_index,
50+
key,
51+
segments_->size());
52+
size_t segment_offset = segments_->Get(segment_index)->offset();
53+
size_t segment_size = segments_->Get(segment_index)->size();
54+
55+
return loader_->load(
56+
/*offset=*/segment_base_offset_ + segment_offset,
57+
segment_size,
58+
DataLoader::SegmentInfo(DataLoader::SegmentInfo::Type::External));
59+
}
60+
}
61+
return Error::NotFound;
62+
}
63+
64+
ET_NODISCARD executorch::runtime::Result<size_t> PteDataMap::get_num_keys()
65+
const {
66+
return named_data_->size();
67+
}
68+
69+
ET_NODISCARD executorch::runtime::Result<const char*> PteDataMap::get_key(
70+
size_t index) const {
71+
ET_CHECK_OR_RETURN_ERROR(
72+
index < named_data_->size(),
73+
InvalidArgument,
74+
"Index out of range: named_data size is %u, received index %zu",
75+
named_data_->size(),
76+
index);
77+
78+
ET_CHECK_OR_RETURN_ERROR(
79+
named_data_->Get(index) != nullptr &&
80+
named_data_->Get(index)->key() != nullptr,
81+
InvalidArgument,
82+
"NamedData at index %zu is null",
83+
index);
84+
return named_data_->Get(index)->key()->c_str();
85+
}
86+
87+
} // namespace internal
88+
} // namespace runtime
89+
} // namespace executorch

runtime/executor/pte_data_map.h

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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+
namespace internal {
31+
32+
/**
33+
* A NamedDataMap implementation for Flatbuffer-serialized named data
34+
* originating from a PTE file.
35+
*/
36+
class PteDataMap final : public NamedDataMap {
37+
public:
38+
/**
39+
* Creates a new DataMap that wraps named_data from the PTE file.
40+
*
41+
* @param[in] loader The DataLoader that accesses the PTE file.
42+
* Note: the loader must outlive the PteDataMap instance.
43+
* @param[in] segment_base_offset The offset to the first segment in the PTE
44+
* file, in bytes.
45+
* @param[in] named_data The named_data from the PTE file. Note: the pointer
46+
* passed here must outlive the PteDataMap instance.
47+
* @param[in] segments The segments from the PTE file. Note: the pointer
48+
* passed here must outlive the PteDataMap instance.
49+
*/
50+
static Result<PteDataMap> create(
51+
DataLoader* loader,
52+
size_t segment_base_offset,
53+
const flatbuffers::Vector<
54+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
55+
const flatbuffers::Vector<
56+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments);
57+
58+
/**
59+
* The PteDataMap currently only handles opaque data that does not contain
60+
* tensor-specific metadata.
61+
*/
62+
ET_NODISCARD
63+
Result<const TensorLayout> get_metadata(
64+
ET_UNUSED const char* key) const override {
65+
return Error::NotImplemented;
66+
}
67+
68+
/**
69+
* Retrieve read-only data for the specified key.
70+
*
71+
* @param[in] key The name of the blob to get data on.
72+
*
73+
* @return error if the key is not present or data cannot be loaded.
74+
*/
75+
ET_NODISCARD
76+
Result<FreeableBuffer> get_data(const char* key) const override;
77+
78+
/**
79+
* The PteDataMap currently does not implement load_into.
80+
*/
81+
ET_NODISCARD 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 Result<size_t> get_num_keys() const override;
92+
93+
/**
94+
* @returns The key at the specified index, error if index out of bounds.
95+
*/
96+
ET_NODISCARD Result<const char*> get_key(size_t index) const override;
97+
98+
// Moveable, to be compatible with Result.
99+
PteDataMap(PteDataMap&&) noexcept = default;
100+
~PteDataMap() override = default;
101+
102+
private:
103+
PteDataMap(
104+
DataLoader* loader,
105+
size_t segment_base_offset,
106+
const flatbuffers::Vector<
107+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data,
108+
const flatbuffers::Vector<
109+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments)
110+
: loader_(loader),
111+
segment_base_offset_(segment_base_offset),
112+
named_data_(named_data),
113+
segments_(segments) {}
114+
115+
// Not copyable or assignable.
116+
PteDataMap(const PteDataMap& rhs) = delete;
117+
PteDataMap& operator=(PteDataMap&& rhs) noexcept = delete;
118+
PteDataMap& operator=(const PteDataMap& rhs) = delete;
119+
120+
// Data loader, used to load segment data.
121+
DataLoader* loader_;
122+
123+
// The offset to the first segment in the PTE file, in bytes.
124+
size_t segment_base_offset_;
125+
126+
// Named data, containing name and segment index.
127+
const flatbuffers::Vector<
128+
flatbuffers::Offset<executorch_flatbuffer::NamedData>>* named_data_;
129+
130+
// Segments, to retrieve offset and size for the loader.
131+
const flatbuffers::Vector<
132+
flatbuffers::Offset<executorch_flatbuffer::DataSegment>>* segments_;
133+
};
134+
135+
} // namespace internal
136+
} // namespace runtime
137+
} // namespace executorch

runtime/executor/targets.bzl

+20
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 = "pte_data_map",
47+
srcs = [
48+
"pte_data_map.cpp",
49+
],
50+
exported_headers = [
51+
"pte_data_map.h",
52+
],
53+
visibility = [
54+
"//executorch/runtime/executor/...",
55+
"@EXECUTORCH_CLIENTS",
56+
],
57+
exported_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(
@@ -77,6 +96,7 @@ def define_common_targets():
7796
preprocessor_flags = _program_preprocessor_flags(),
7897
exported_deps = [
7998
":memory_manager",
99+
":pte_data_map",
80100
"//executorch/runtime/backend:interface",
81101
"//executorch/runtime/core:core",
82102
"//executorch/runtime/core:named_data_map",

0 commit comments

Comments
 (0)