Skip to content

Commit 0d0dd1d

Browse files
lucylqfacebook-github-bot
authored andcommitted
Update runtime to read new schema (#1369)
Summary: Pull Request resolved: #1369 * Runtime branches on `constant_buffer` / `constant_segment`. * Throw error if both contain items. Reviewed By: dbort Differential Revision: D51638620 fbshipit-source-id: 03bbe2f502ab77e06c92ad55aa0ff368babe9b68
1 parent 9beb594 commit 0d0dd1d

3 files changed

Lines changed: 122 additions & 26 deletions

File tree

runtime/executor/program.cpp

Lines changed: 107 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,56 @@ Result<executorch_flatbuffer::ExecutionPlan*> get_execution_plan(
144144
const executorch_flatbuffer::Program* flatbuffer_program =
145145
executorch_flatbuffer::GetProgram(program_data->data());
146146

147-
// The FreeableBuffer owns the data that flatbuffer_program points into. Also
148-
// keep a pointer to the loader so it can load more segments when necessary.
149-
return Program(
150-
loader,
151-
segment_base_offset,
152-
std::move(program_data.get()),
153-
flatbuffer_program);
147+
// Constant data may live inside the flatbuffer data (constant_buffer) or in a
148+
// separate segment (constant_segment). It should not be in both.
149+
const auto& constant_buffer = flatbuffer_program->constant_buffer();
150+
const auto& constant_segment = flatbuffer_program->constant_segment();
151+
152+
// Check if the constant data is inside a separate segment.
153+
if (constant_segment != nullptr && constant_segment->offsets()->size() > 0) {
154+
ET_CHECK_OR_RETURN_ERROR(
155+
constant_buffer->size() == 0,
156+
InvalidState,
157+
"constant_buffer contains %u items, constant_segment.offsets contains %u items. Only one should be used.",
158+
constant_buffer->size(),
159+
constant_segment->offsets()->size());
160+
161+
// Load constant segment.
162+
// TODO(T171839323): Add test for segment_index > num available segments.
163+
ET_CHECK_OR_RETURN_ERROR(
164+
constant_segment->segment_index() <
165+
flatbuffer_program->segments()->size(),
166+
InvalidArgument,
167+
"Constant segment index %d invalid for program segments range %d",
168+
constant_segment->segment_index(),
169+
flatbuffer_program->segments()->size());
170+
171+
const executorch_flatbuffer::DataSegment* data_segment =
172+
flatbuffer_program->segments()->Get(constant_segment->segment_index());
173+
Result<FreeableBuffer> constant_segment_data = loader->Load(
174+
segment_base_offset + data_segment->offset(), data_segment->size());
175+
if (!constant_segment_data.ok()) {
176+
return constant_segment_data.error();
177+
}
178+
// The FreeableBuffer owns the data that flatbuffer_program points into.
179+
// Also keep a pointer to the loader so it can load more segments when
180+
// necessary.
181+
return Program(
182+
loader,
183+
segment_base_offset,
184+
std::move(program_data.get()),
185+
flatbuffer_program,
186+
std::move(constant_segment_data.get()));
187+
} else {
188+
// The constant data is stored inside the flatbuffer, so this program does
189+
// not contain a separate segment for it.
190+
return Program(
191+
loader,
192+
segment_base_offset,
193+
std::move(program_data.get()),
194+
flatbuffer_program,
195+
/*constant_segment_data=*/FreeableBuffer{});
196+
}
154197
}
155198

156199
size_t Program::num_methods() const {
@@ -192,21 +235,67 @@ Result<MethodMeta> Program::method_meta(const char* method_name) const {
192235
}
193236

194237
Result<const void*> Program::get_constant_buffer_data(
195-
size_t buffer_index) const {
238+
size_t buffer_index,
239+
size_t nbytes) const {
196240
auto internal_program =
197241
static_cast<const executorch_flatbuffer::Program*>(internal_program_);
198-
size_t size = internal_program->constant_buffer()->size();
199-
ET_CHECK_OR_RETURN_ERROR(
200-
buffer_index < size,
201-
InvalidArgument,
202-
"Constant buffer %zu out of program buffer range %zu",
203-
buffer_index,
204-
size);
205242

206-
const auto& constant_buffer = *internal_program->constant_buffer();
243+
// Constant data is either in a separate segment (constant_segment_data) and
244+
// loaded during Program::load, or stored inside the flatbuffer data
245+
// (constant_buffer).
246+
if (constant_segment_data_.data() != nullptr) {
247+
size_t num_elems = internal_program->constant_segment()->offsets()->size();
248+
ET_CHECK_OR_RETURN_ERROR(
249+
buffer_index < num_elems,
250+
InvalidArgument,
251+
"Constant segment buffer index %zu invalid for program constant segment range %zu",
252+
buffer_index,
253+
num_elems);
254+
255+
// All constant data is stored in one segment, with each tensor aligned to
256+
// @executorch_tensor_alignment. Tensor offsets are stored in the flatbuffer
257+
// data in Program.constant_segment.offsets.
258+
// The constant data at buffer_index is located at: base address of the
259+
// constant segment + offset for tensor at buffer_index.
260+
uint64_t offset = static_cast<uint64_t>(
261+
(*internal_program->constant_segment()->offsets())[buffer_index]);
207262

208-
return static_cast<const void*>(
209-
constant_buffer[buffer_index]->storage()->data());
263+
size_t size = constant_segment_data_.size();
264+
ET_CHECK_OR_RETURN_ERROR(
265+
offset + nbytes <= size,
266+
InvalidArgument,
267+
"Constant segment offset %" PRIu64
268+
" + size_bytes %zu invalid for program constant segment size %zu",
269+
offset,
270+
nbytes,
271+
size);
272+
273+
// Offset is wrt the beginning of the constant segment.
274+
return static_cast<const void*>(
275+
static_cast<const unsigned char*>(constant_segment_data_.data()) +
276+
offset);
277+
} else {
278+
// Otherwise, the constant data is stored inside Program.constant_buffer.
279+
size_t num_elems = internal_program->constant_buffer()->size();
280+
ET_CHECK_OR_RETURN_ERROR(
281+
buffer_index < num_elems,
282+
InvalidArgument,
283+
"Constant buffer index %zu invalid for program constant buffer range %zu",
284+
buffer_index,
285+
num_elems);
286+
287+
const auto& constant_buffer = *internal_program->constant_buffer();
288+
289+
ET_CHECK_OR_RETURN_ERROR(
290+
constant_buffer[buffer_index]->storage()->size() <= nbytes,
291+
InvalidArgument,
292+
"Constant buffer size %u larger than allocated nbytes %zu",
293+
constant_buffer[buffer_index]->storage()->size(),
294+
nbytes);
295+
296+
return static_cast<const void*>(
297+
constant_buffer[buffer_index]->storage()->data());
298+
}
210299
}
211300

212301
Result<int64_t> Program::get_non_const_buffer_size(

runtime/executor/program.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,13 @@ class Program final {
8989
~Program() = default;
9090

9191
/**
92-
* Get the constant buffer inside Program with index buffer_idx
93-
* @param[in] buffer_idx the index of the buffer in the constant_buffer
94-
* @return The buffer with corresponding index
92+
* Get the constant buffer inside Program with index buffer_idx.
93+
* @param[in] buffer_idx the index of the buffer in the constant_buffer.
94+
* @param[in] nbytes the number of bytes to read from the buffer.
95+
* @return The buffer with corresponding index.
9596
*/
96-
Result<const void*> get_constant_buffer_data(size_t buffer_idx) const;
97+
Result<const void*> get_constant_buffer_data(size_t buffer_idx, size_t nbytes)
98+
const;
9799

98100
/**
99101
* Returns the number of methods in the program.
@@ -254,12 +256,14 @@ class Program final {
254256
DataLoader* loader,
255257
size_t segment_base_offset,
256258
FreeableBuffer&& program_data,
257-
const executorch_flatbuffer::Program* internal_program)
259+
const executorch_flatbuffer::Program* internal_program,
260+
FreeableBuffer&& constant_segment_data)
258261
: program_data_(std::move(program_data)),
259262
// Don't need the loader if there are no segments.
260263
loader_(segment_base_offset > 0 ? loader : nullptr),
261264
internal_program_(internal_program),
262-
segment_base_offset_(segment_base_offset) {}
265+
segment_base_offset_(segment_base_offset),
266+
constant_segment_data_(std::move(constant_segment_data)) {}
263267

264268
// Not copyable or assignable.
265269
Program(const Program& rhs) = delete;
@@ -279,6 +283,9 @@ class Program final {
279283
/// The offset to the first segment, in bytes. If zero, no segments should
280284
/// be present in internal_program_.
281285
size_t segment_base_offset_;
286+
287+
/// Constant segment data.
288+
FreeableBuffer constant_segment_data_;
282289
};
283290

284291
} // namespace executor

runtime/executor/tensor_parser_exec_aten.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ __ET_NODISCARD Result<void*> getTensorDataPtr(
5555
size_t nbytes,
5656
HierarchicalAllocator* allocator) {
5757
if (s_tensor->constant_buffer_idx() > 0) {
58-
auto data =
59-
program->get_constant_buffer_data(s_tensor->constant_buffer_idx());
58+
auto data = program->get_constant_buffer_data(
59+
s_tensor->constant_buffer_idx(), nbytes);
6060
if (!data.ok()) {
6161
return data.error();
6262
}

0 commit comments

Comments
 (0)