Skip to content

Commit 76ddea4

Browse files
committed
[executorch][flat tensor] Store number of external tensors in flatbuffer
Store the number of external tensors in each ExecutionPlan. This saves time during loading, as we can directly allocate memory for external tensors without doing a pass to count how many external tensors require allocation. Differential Revision: [D69618283](https://our.internmc.facebook.com/intern/diff/D69618283/) ghstack-source-id: 266371204 Pull Request resolved: #8483
1 parent 5939287 commit 76ddea4

File tree

6 files changed

+18
-46
lines changed

6 files changed

+18
-46
lines changed

exir/emit/_emit_program.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def emit_program(
163163
operator_cache={},
164164
delegate_cache={},
165165
emit_stacktrace=emit_stacktrace,
166+
num_external_constants=0,
166167
)
167168

168169
gm = _remove_non_user_outputs(exported_program)

exir/emit/_emitter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class _EmitterState:
143143
"""
144144

145145
values: List[EValue]
146+
num_external_constants: int
146147
operators: List[Operator]
147148
delegates: List[BackendDelegate]
148149
operator_cache: Dict[Tuple[str, str], int]
@@ -407,6 +408,7 @@ def _save_new_const_tensor(
407408
self.program_state.external_constant_map[constant_tag][
408409
spec.extra_tensor_info.fully_qualified_name # pyre-ignore Undefined attribute [16]: `Optional` has no attribute `fully_qualified_name`.
409410
] = buffer_idx
411+
self.emitter_state.num_external_constants += 1
410412
# Tensor is mutable with initial state. Place into mutable segment
411413
elif allocation_info:
412414
buffer_idx = len(self.program_state.mutable_buffer)
@@ -1358,6 +1360,7 @@ def _emit_prim_getters(self, prim_getters: Dict[str, Any]) -> List[ExecutionPlan
13581360
delegates=[],
13591361
non_const_buffer_sizes=[0],
13601362
container_meta_type=ContainerMetadata("", spec),
1363+
num_external_constants=0,
13611364
)
13621365
)
13631366
return plans
@@ -1739,4 +1742,5 @@ def plan(self) -> ExecutionPlan:
17391742
self.module.meta["non_const_buffer_sizes"],
17401743
),
17411744
container_meta_type=self.container_meta_type,
1745+
num_external_constants=self.emitter_state.num_external_constants,
17421746
)

exir/schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ class ExecutionPlan:
276276
# Runtime should use the len(constant_buffer) as the ground truch of
277277
# constant memory buffer size, and ignore non_const_buffer_sizes[0].
278278
non_const_buffer_sizes: List[int]
279+
num_external_constants: int
279280

280281

281282
@dataclass

runtime/executor/method.cpp

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -289,42 +289,6 @@ Result<bool> parse_cond_value(const EValue& cond_value) {
289289

290290
} // namespace
291291

292-
Result<size_t> Method::get_num_external_constants() {
293-
auto flatbuffer_values = serialization_plan_->values();
294-
size_t n_value = flatbuffer_values->size();
295-
296-
size_t num_external_constants = 0;
297-
for (size_t i = 0; i < n_value; ++i) {
298-
auto serialization_value = flatbuffer_values->Get(i);
299-
// Ensure that the `val_as_X()` calls will return non-null pointers.
300-
ET_CHECK_OR_RETURN_ERROR(
301-
serialization_value != nullptr &&
302-
(serialization_value->val_type() ==
303-
executorch_flatbuffer::KernelTypes::Null ||
304-
serialization_value->val() != nullptr),
305-
InvalidProgram,
306-
"Null value at index %" ET_PRIsize_t,
307-
i);
308-
// Ignore non-tensor types.
309-
if (serialization_value->val_type() !=
310-
executorch_flatbuffer::KernelTypes::Tensor) {
311-
continue;
312-
}
313-
const auto s_tensor = static_cast<const executorch_flatbuffer::Tensor*>(
314-
serialization_value->val());
315-
316-
// An external constant is tagged with EXTERNAL and has no
317-
// allocation_info.
318-
if (s_tensor->extra_tensor_info() != nullptr &&
319-
s_tensor->extra_tensor_info()->location() ==
320-
executorch_flatbuffer::TensorDataLocation::EXTERNAL &&
321-
s_tensor->allocation_info() == nullptr) {
322-
num_external_constants++;
323-
}
324-
}
325-
return num_external_constants;
326-
}
327-
328292
bool key_exists(const char* key, NamedData* external_constants, int num_keys) {
329293
for (int i = 0; i < num_keys; i++) {
330294
if (strcmp(key, external_constants[i].key) == 0) {
@@ -342,6 +306,15 @@ Error Method::parse_external_constants(const NamedDataMap* named_data_map) {
342306
int index = 0;
343307
for (size_t i = 0; i < n_value; ++i) {
344308
auto serialization_value = flatbuffer_values->Get(i);
309+
// Ensure that the `val_as_X()` calls will return non-null pointers.
310+
ET_CHECK_OR_RETURN_ERROR(
311+
serialization_value != nullptr &&
312+
(serialization_value->val_type() ==
313+
executorch_flatbuffer::KernelTypes::Null ||
314+
serialization_value->val() != nullptr),
315+
InvalidProgram,
316+
"Null value at index %" ET_PRIsize_t,
317+
i);
345318
// Ignore non-tensor types.
346319
if (serialization_value->val_type() !=
347320
executorch_flatbuffer::KernelTypes::Tensor) {
@@ -412,11 +385,7 @@ Error Method::parse_values(const NamedDataMap* named_data_map) {
412385
}
413386

414387
// Check if there are any external constants.
415-
Result<size_t> num_external_constants = get_num_external_constants();
416-
if (!num_external_constants.ok()) {
417-
return num_external_constants.error();
418-
}
419-
num_external_constants_ = *num_external_constants;
388+
num_external_constants_ = serialization_plan_->num_external_constants();
420389
if (num_external_constants_ > 0) {
421390
// Allocate space for external tensors.
422391
external_constants_ =

runtime/executor/method.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,6 @@ class Method final {
358358
NamedData* external_constants_;
359359
size_t num_external_constants_ = 0;
360360

361-
/**
362-
* Counts the number of external constants for this method.
363-
*/
364-
ET_NODISCARD Result<size_t> get_num_external_constants();
365-
366361
/**
367362
* Parses the flatbuffer for constant tensors tagged as EXTERNAL.
368363
* Retrieves the external constants using the named_data_map and places them

schema/program.fbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ table ExecutionPlan {
386386
// constants memory buffer size, and ignore non_const_buffer_sizes[0].
387387
non_const_buffer_sizes: [int64];
388388

389+
// Number of external constants used in this ExecutionPlan.
390+
num_external_constants: uint32;
389391
}
390392

391393
// Constant tensor data stored directly in the flatbuffer.

0 commit comments

Comments
 (0)