Skip to content

Commit d0f486a

Browse files
authored
Make _get_program_from_buffer work for bundled programs take 2 (#14503)
This is a re-upload of #14435, with variables moved inside #ifdef to not get unused variables when building without devtools. --------------------------------------- Add some cmake to only do this if executorch is built with bundleio. codegen/tools subdirectory include needs to be moved in top-level CmakeLists.txt to have access to the bundled_program target. Follow-up patch to enable the fix in arm backend. Signed-off-by: Erik Lundell <[email protected]>
1 parent b7ac647 commit d0f486a

File tree

6 files changed

+54
-19
lines changed

6 files changed

+54
-19
lines changed

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,6 @@ endif()
729729

730730
if(EXECUTORCH_BUILD_PYBIND)
731731

732-
# Add codegen tools subdirectory for selective_build pybind module
733-
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/codegen/tools)
734-
735732
if(NOT EXECUTORCH_BUILD_EXTENSION_DATA_LOADER)
736733
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extension/data_loader)
737734
endif()
@@ -740,6 +737,9 @@ if(EXECUTORCH_BUILD_PYBIND)
740737
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/devtools)
741738
endif()
742739

740+
# Add codegen tools subdirectory for selective_build pybind module
741+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/codegen/tools)
742+
743743
# Create bundled_module target only for pybindings when bundled_program exists
744744
# This target has hard dependencies on devtools generated headers
745745
if(TARGET bundled_program)

codegen/tools/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright (c) Meta Platforms, Inc. and affiliates.
22
# All rights reserved.
3+
# Copyright 2025 Arm Limited and/or its affiliates.
34
#
45
# This source code is licensed under the BSD-style license found in the
56
# LICENSE file in the root directory of this source tree.
@@ -37,6 +38,10 @@ target_compile_options(
3738
# Unix builds, but we also build on Windows where it's ignored
3839

3940
# Link against required libraries
41+
if(TARGET bundled_program)
42+
target_compile_definitions(selective_build PRIVATE -DET_BUNDLE_IO)
43+
target_link_libraries(selective_build PRIVATE bundled_program)
44+
endif()
4045
target_link_libraries(selective_build PRIVATE executorch_core program_schema)
4146

4247
# Install the module

codegen/tools/selective_build.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
/*
22
* Copyright (c) Meta Platforms, Inc. and affiliates.
33
* All rights reserved.
4+
* Copyright 2025 Arm Limited and/or its affiliates.
45
*
56
* This source code is licensed under the BSD-style license found in the
67
* LICENSE file in the root directory of this source tree.
78
*/
89

10+
#include <executorch/runtime/platform/assert.h>
11+
#include <executorch/schema/program_generated.h>
912
#include <pybind11/pybind11.h>
1013
#include <pybind11/stl.h>
1114

12-
#include <executorch/runtime/platform/assert.h>
13-
#include <executorch/schema/program_generated.h>
15+
#ifdef ET_BUNDLE_IO
16+
#include <executorch/devtools/bundled_program/bundled_program.h>
17+
#include <stdexcept>
18+
#endif
1419

1520
namespace py = pybind11;
1621

@@ -186,8 +191,39 @@ get_kernel_tensor_metadatas_from_execution_plan(
186191

187192
const executorch_flatbuffer::Program* _get_program_from_buffer(
188193
const py::bytes& buffer) {
194+
// Access the Python bytes without copying and get raw pointer/size.
195+
const std::string_view sv = buffer.cast<std::string_view>();
196+
#ifdef ET_BUNDLE_IO
197+
void* buf_ptr = const_cast<void*>(static_cast<const void*>(sv.data()));
198+
const size_t buf_len = sv.size();
199+
200+
// If this is a bundled program, extract the inner ExecuTorch program bytes.
201+
if (executorch::bundled_program::is_bundled_program(buf_ptr, buf_len)) {
202+
const void* program_data = nullptr;
203+
size_t program_size = 0;
204+
205+
const auto status = executorch::bundled_program::get_program_data(
206+
buf_ptr, // serialized BundledProgram start
207+
buf_len, // total size of the BundledProgram blob
208+
&program_data, // [out] pointer to inner .pte bytes
209+
&program_size // [out] size of inner .pte bytes
210+
);
211+
212+
if (status != ::executorch::runtime::Error::Ok || program_data == nullptr ||
213+
program_size == 0) {
214+
throw std::runtime_error(
215+
"bundled_program::get_program_data() failed or returned empty data");
216+
}
217+
218+
// program_data points directly at the flatbuffer-encoded Program region.
219+
return executorch_flatbuffer::GetProgram(
220+
reinterpret_cast<const uint8_t*>(program_data));
221+
}
222+
#endif
223+
// Otherwise treat the buffer as a raw .pte (flatbuffer Program with optional
224+
// extended header).
189225
return executorch_flatbuffer::GetProgram(
190-
buffer.cast<std::string_view>().data());
226+
reinterpret_cast<const uint8_t*>(sv.data()));
191227
}
192228

193229
py::list _get_program_operators(const executorch_flatbuffer::Program* program) {

docs/source/backends-arm-ethos-u.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ You can see how this coupling between the memory mode and runtime application i
268268

269269
The arm_executor_runner supports [bundled-io](https://docs.pytorch.org/executorch/0.4/bundled-io.html) and [ETdump](https://docs.pytorch.org/executorch/stable/etdump.html) debugging tools.
270270

271-
To enable bundled-io, set `EXECUTORCH_BUILD_DEVTOOLS` when building Executorch and `DET_BUNDLE_IO` when building the executor_runner. Currently using bundled-io requires specifying your
272-
non delegated Aten ops manually by setting `EXECUTORCH_SELECT_OPS_LIST`. To enable ETdump, set `EXECUTORCH_BUILD_ARM_ETDUMP` when building Executorch and `DEXECUTORCH_ENABLE_EVENT_TRACER`
271+
To enable bundled-io, set `EXECUTORCH_BUILD_DEVTOOLS` when building Executorch and `DET_BUNDLE_IO` when building the executor_runner. To enable ETdump, set `EXECUTORCH_BUILD_ARM_ETDUMP` when building Executorch and `DEXECUTORCH_ENABLE_EVENT_TRACER`
273272
when building the executor_runner.
274273

275274

examples/arm/executor_runner/CMakeLists.txt

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,10 @@ list(
235235
-Map=arm_executor_runner.map
236236
)
237237

238-
# Prefer to generate kernel bindings from model file if possible, which is when
239-
# 1. Not building for semihosting 2. Not building with bundleio If that is not
240-
# the case, fallback to select_ops_list If the model file does not contain any
241-
# aten ops, a workaround is currently needed to avoid crashing.
238+
# Figure out which ops to include: For semihosting build, use
239+
# (user-set)SELECT_OPS_MODEL variable. For normal build, use
240+
# EXECUTORCH_SELECT_OPS_MODEL to include ops automatically. If the pte contains
241+
# no undelegated ops, use neither.
242242
execute_process(
243243
COMMAND
244244
python "${ET_DIR_PATH}/codegen/tools/gen_oplist.py"
@@ -264,11 +264,6 @@ elseif(${FOUND_OPS_IN_FILE})
264264
message(
265265
"gen_oplist: EXECUTORCH_SELECT_OPS_MODEL=${ET_PTE_FILE_PATH} is used to auto generate ops from"
266266
)
267-
elseif(NOT ${FOUND_OPS_IN_FILE} AND ${ET_BUNDLE_IO})
268-
set(EXECUTORCH_SELECT_OPS_MODEL "")
269-
message(
270-
"gen_oplist: Building with ET_BUNDLE_IO and .bpte is not supported to auto generate ops from will use EXECUTORCH_SELECT_OPS_LIST=${EXECUTORCH_SELECT_OPS_LIST}"
271-
)
272267
else()
273268
set(EXECUTORCH_SELECT_OPS_LIST "")
274269
set(EXECUTORCH_SELECT_OPS_MODEL "")

examples/arm/run.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ function help() {
5353
echo " --no_delegate Do not delegate the model (can't override builtin models)"
5454
echo " --no_quantize Do not quantize the model (can't override builtin models)"
5555
echo " --portable_kernels=<OPS> TO BE DEPRECATED: Alias to select_ops_list."
56-
echo " --select_ops_list=<OPS> Comma separated list of portable (non delegated) kernels to include Default: ${select_ops_list}"
57-
echo " NOTE: This is used when select_ops_model is not possible to use, e.g. for semihosting or bundleio."
56+
echo " --select_ops_list=<OPS> Comma separated list of portable (non delagated) kernels to include Default: ${select_ops_list}"
57+
echo " NOTE: This is only used when building for semihosting."
5858
echo " See https://docs.pytorch.org/executorch/stable/kernel-library-selective-build.html for more information."
5959
echo " --target=<TARGET> Target to build and run for Default: ${target}"
6060
echo " --output=<FOLDER> Target build output folder Default: ${output_folder}"

0 commit comments

Comments
 (0)