Skip to content

Commit cf28248

Browse files
zingoAdrianLundellBujSetperheld
authored
Arm backend: Add support for Zephyr as a external module (#16294)
### Summary This commit has everything needed to build ExecuTorch from Zephyr and include it as a external module without having any changes in zephyr. Based on code by BujSet. ### Test plan Tested by hand. Plan to update GitHub testing for this in later PR Co-authored-by: BujSet <[ranganath1000@gmail.com](mailto:ranganath1000@gmail.com)> Co-authored-by: Adrian Lundell <[adrian.lundell@arm.com](mailto:adrian.lundell@arm.com)> Co-authored-by: Zingo Andersen <[zingo.andersen@arm.com](mailto:zingo.andersen@arm.com)> Co-authored-by: Per Held <[per.held@arm.com](mailto:per.held@arm.com)> --------- Signed-off-by: Zingo Andersen <Zingo.Andersen@arm.com> Co-authored-by: Adrian Lundell <adrian.lundell@arm.com> Co-authored-by: BujSet <ranganath1000@gmail.com> Co-authored-by: Zingo Andersen <zingo.andersen@arm.com> Co-authored-by: Per Held <per.held@arm.com>
1 parent 0fb422f commit cf28248

File tree

13 files changed

+1218
-5
lines changed

13 files changed

+1218
-5
lines changed

backends/arm/runtime/EthosUBackend.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
* ethos-u-core-driver for hardware interaction.
1111
*/
1212

13+
// Workaround for runtime/core/portable_type/c10/c10/util/Float16-math.h
14+
#if defined(__GNUC__) && defined(__ZEPHYR__)
15+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
16+
#endif
17+
1318
#include <cstdint>
1419
#include <cstring>
1520
#include <memory>

backends/cortex_m/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ target_link_libraries(
8080
cortex_m_kernels
8181
PRIVATE cmsis-nn
8282
PRIVATE executorch
83+
PRIVATE kernels_util_all_deps
8384
)
8485

8586
# Include directories for cortex_m_kernels

examples/arm/zephyr/CMakeLists.txt

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
# Copyright 2025 Arm Limited and/or its affiliates.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
cmake_minimum_required(VERSION 3.24)
8+
9+
# Disable install(rule) generation while building under Zephyr. The sample
10+
# application never runs `cmake --install`, and skipping the rules avoids export
11+
# dependency checks when Zephyr provides targets such as ethosu_core_driver.
12+
set(CMAKE_SKIP_INSTALL_RULES
13+
ON
14+
CACHE BOOL "" FORCE
15+
)
16+
17+
# Use configuration overlay to disable default portable ops to enable selective
18+
# operator build
19+
set(ET_PTE_FILE_PATH
20+
""
21+
CACHE FILEPATH "Path to the ExecuTorch .pte (or .bpte) model to embed"
22+
)
23+
set(ET_PTE_SECTION
24+
"network_model_sec"
25+
CACHE STRING "Section attribute used for the generated model data"
26+
)
27+
28+
if(NOT ET_PTE_FILE_PATH)
29+
message(
30+
FATAL_ERROR
31+
"ET_PTE_FILE_PATH must point to the ExecuTorch .pte (or .bpte) model to embed."
32+
)
33+
endif()
34+
35+
if(NOT IS_ABSOLUTE "${ET_PTE_FILE_PATH}")
36+
get_filename_component(
37+
ET_PTE_FILE_PATH "${ET_PTE_FILE_PATH}" ABSOLUTE BASE_DIR
38+
"${CMAKE_CURRENT_SOURCE_DIR}"
39+
)
40+
endif()
41+
42+
if(NOT EXISTS "${ET_PTE_FILE_PATH}")
43+
message(
44+
FATAL_ERROR
45+
"Could not find ExecuTorch model at ET_PTE_FILE_PATH: ${ET_PTE_FILE_PATH}"
46+
)
47+
endif()
48+
49+
set(ET_PTE_FILE_PATH
50+
"${ET_PTE_FILE_PATH}"
51+
CACHE FILEPATH "Path to the ExecuTorch .pte (or .bpte) model to embed"
52+
FORCE
53+
)
54+
55+
execute_process(
56+
COMMAND
57+
python "${CMAKE_CURRENT_LIST_DIR}/../../../codegen/tools/gen_oplist.py"
58+
--model_file_path=${ET_PTE_FILE_PATH}
59+
--output_path=${CMAKE_CURRENT_BINARY_DIR}/temp.yaml
60+
OUTPUT_VARIABLE CMD_RESULT
61+
)
62+
63+
if(CMD_RESULT MATCHES "aten::" OR CMD_RESULT MATCHES "dim_order_ops::")
64+
set(FOUND_OPS_IN_FILE "true")
65+
else()
66+
set(FOUND_OPS_IN_FILE "false")
67+
endif()
68+
69+
if(${FOUND_OPS_IN_FILE})
70+
set(EXECUTORCH_SELECT_OPS_LIST "")
71+
set(EXECUTORCH_SELECT_OPS_MODEL
72+
"${ET_PTE_FILE_PATH}"
73+
CACHE STRING "Select operators from this ExecuTorch model" FORCE
74+
)
75+
set(_EXECUTORCH_GEN_ZEPHYR_PORTABLE_OPS ON)
76+
message(
77+
"gen_oplist: EXECUTORCH_SELECT_OPS_MODEL=${ET_PTE_FILE_PATH} is used to auto generate ops from"
78+
)
79+
else()
80+
set(EXECUTORCH_SELECT_OPS_LIST "")
81+
set(EXECUTORCH_SELECT_OPS_MODEL "")
82+
set(_EXECUTORCH_GEN_ZEPHYR_PORTABLE_OPS OFF)
83+
message(
84+
"gen_oplist: No non delagated ops was found in ${ET_PTE_FILE_PATH} no ops added to build"
85+
)
86+
endif()
87+
88+
set(CONF_FILE "${CMAKE_CURRENT_SOURCE_DIR}/prj.conf")
89+
90+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
91+
project(executorch_executor_runner)
92+
93+
find_package(
94+
Python3
95+
COMPONENTS Interpreter
96+
REQUIRED
97+
)
98+
99+
set(CMAKE_CXX_FLAGS
100+
"${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-float-conversion -Wno-double-promotion -ffunction-sections -fdata-sections"
101+
)
102+
103+
# Always use selective build since embedded devices are resource constrained
104+
105+
# Include ExecuTorch selective build utilities Use EXECUTORCH_DIR if available,
106+
# otherwise use Zephyr's module discovery
107+
if(NOT DEFINED EXECUTORCH_DIR)
108+
message(
109+
STATUS
110+
"ZEPHYR_EXECUTORCH_MODULE_DIR set to : ${ZEPHYR_EXECUTORCH_MODULE_DIR}"
111+
)
112+
if(DEFINED ZEPHYR_EXECUTORCH_MODULE_DIR)
113+
set(EXECUTORCH_DIR ${ZEPHYR_EXECUTORCH_MODULE_DIR})
114+
message(
115+
STATUS "Using Zephyr module discovery: EXECUTORCH_DIR=${EXECUTORCH_DIR}"
116+
)
117+
else()
118+
message(
119+
FATAL_ERROR
120+
"ExecutorTorch module not found. Ensure it's properly configured in your Zephyr workspace."
121+
)
122+
endif()
123+
else()
124+
message(STATUS "Using predefined EXECUTORCH_DIR=${EXECUTORCH_DIR}")
125+
endif()
126+
127+
# Set EXECUTORCH_ROOT for the Codegen.cmake file
128+
set(EXECUTORCH_ROOT ${EXECUTORCH_DIR})
129+
130+
# Ensure the portable kernels target exists even when portable ops are disabled
131+
# in the global build.
132+
if(NOT TARGET portable_kernels)
133+
set(EXECUTORCH_PORTABLE_BUILD_KERNELS_ONLY ON)
134+
add_subdirectory(
135+
${EXECUTORCH_DIR}/kernels/portable
136+
${CMAKE_CURRENT_BINARY_DIR}/executorch/kernels/portable
137+
)
138+
unset(EXECUTORCH_PORTABLE_BUILD_KERNELS_ONLY)
139+
endif()
140+
set(EXECUTORCH_OPS_LIB "")
141+
if(_EXECUTORCH_GEN_ZEPHYR_PORTABLE_OPS)
142+
include(${EXECUTORCH_DIR}/tools/cmake/Utils.cmake)
143+
include(${EXECUTORCH_DIR}/tools/cmake/Codegen.cmake)
144+
if(NOT DEFINED EXECUTORCH_ENABLE_DTYPE_SELECTIVE_BUILD)
145+
set(EXECUTORCH_ENABLE_DTYPE_SELECTIVE_BUILD "")
146+
endif()
147+
gen_selected_ops(
148+
LIB_NAME
149+
"cpu_portable_ops_lib"
150+
OPS_SCHEMA_YAML
151+
""
152+
ROOT_OPS
153+
"${EXECUTORCH_SELECT_OPS_LIST}"
154+
INCLUDE_ALL_OPS
155+
""
156+
OPS_FROM_MODEL
157+
"${EXECUTORCH_SELECT_OPS_MODEL}"
158+
DTYPE_SELECTIVE_BUILD
159+
"${EXECUTORCH_ENABLE_DTYPE_SELECTIVE_BUILD}"
160+
)
161+
generate_bindings_for_kernels(
162+
LIB_NAME "cpu_portable_ops_lib" FUNCTIONS_YAML
163+
${EXECUTORCH_DIR}/kernels/portable/functions.yaml DTYPE_SELECTIVE_BUILD
164+
"${EXECUTORCH_ENABLE_DTYPE_SELECTIVE_BUILD}"
165+
)
166+
gen_operators_lib(
167+
LIB_NAME
168+
"cpu_portable_ops_lib"
169+
KERNEL_LIBS
170+
portable_kernels
171+
DEPS
172+
executorch
173+
DTYPE_SELECTIVE_BUILD
174+
"${EXECUTORCH_ENABLE_DTYPE_SELECTIVE_BUILD}"
175+
)
176+
set(EXECUTORCH_OPS_LIB "cpu_portable_ops_lib")
177+
endif()
178+
179+
set(_local_flatcc_root ${CMAKE_BINARY_DIR}/flatcc_src)
180+
if(NOT EXISTS ${_local_flatcc_root}/CMakeLists.txt)
181+
file(MAKE_DIRECTORY ${_local_flatcc_root})
182+
execute_process(
183+
COMMAND ${CMAKE_COMMAND} -E copy_directory
184+
${EXECUTORCH_DIR}/third-party/flatcc ${_local_flatcc_root}
185+
)
186+
endif()
187+
set(EXECUTORCH_FLATCC_SOURCE_ROOT
188+
${_local_flatcc_root}
189+
CACHE PATH "" FORCE
190+
)
191+
set(EXECUTORCH_FLATCC_INSTALL_ROOT
192+
${_local_flatcc_root}
193+
CACHE PATH "" FORCE
194+
)
195+
196+
set(app_sources
197+
src/arm_executor_runner.cpp
198+
${EXECUTORCH_DIR}/examples/arm/executor_runner/arm_memory_allocator.cpp
199+
)
200+
target_sources(app PRIVATE ${app_sources})
201+
202+
set(_model_pte_header ${CMAKE_CURRENT_BINARY_DIR}/model_pte.h)
203+
add_custom_command(
204+
OUTPUT ${_model_pte_header}
205+
COMMAND
206+
${Python3_EXECUTABLE}
207+
${EXECUTORCH_DIR}/examples/arm/executor_runner/pte_to_header.py --pte
208+
${ET_PTE_FILE_PATH} --outdir ${CMAKE_CURRENT_BINARY_DIR} --section
209+
${ET_PTE_SECTION}
210+
DEPENDS ${ET_PTE_FILE_PATH}
211+
${EXECUTORCH_DIR}/examples/arm/executor_runner/pte_to_header.py
212+
COMMENT "Converting ${ET_PTE_FILE_PATH} to model_pte.h"
213+
)
214+
add_custom_target(gen_model_header DEPENDS ${_model_pte_header})
215+
add_dependencies(app gen_model_header)
216+
217+
if(DEFINED CONFIG_EXECUTORCH_METHOD_ALLOCATOR_POOL_SIZE)
218+
target_compile_definitions(
219+
app
220+
PRIVATE
221+
ET_ARM_METHOD_ALLOCATOR_POOL_SIZE=${CONFIG_EXECUTORCH_METHOD_ALLOCATOR_POOL_SIZE}
222+
)
223+
endif()
224+
if(DEFINED CONFIG_EXECUTORCH_TEMP_ALLOCATOR_POOL_SIZE)
225+
target_compile_definitions(
226+
app
227+
PRIVATE
228+
ET_ARM_BAREMETAL_SCRATCH_TEMP_ALLOCATOR_POOL_SIZE=${CONFIG_EXECUTORCH_TEMP_ALLOCATOR_POOL_SIZE}
229+
)
230+
endif()
231+
232+
# Link with ExecuTorch and our operators library
233+
target_link_libraries(app PRIVATE libexecutorch)
234+
if(EXECUTORCH_OPS_LIB)
235+
target_link_libraries(app PRIVATE ${EXECUTORCH_OPS_LIB})
236+
endif()
237+
if(CONFIG_CPU_CORTEX_M)
238+
if(TARGET cortex_m_ops_lib)
239+
target_link_libraries(app PRIVATE cortex_m_ops_lib)
240+
endif()
241+
if(TARGET cortex_m_kernels)
242+
target_link_libraries(app PRIVATE cortex_m_kernels)
243+
endif()
244+
endif()
245+
if(TARGET executorch_delegate_ethos_u)
246+
target_link_libraries(app PRIVATE executorch_delegate_ethos_u)
247+
endif()
248+
if(TARGET ethosu_core_driver)
249+
target_link_libraries(app PRIVATE ethosu_core_driver)
250+
endif()
251+
252+
# Add include directories for sources and generated headers
253+
target_include_directories(app PRIVATE src ${CMAKE_CURRENT_BINARY_DIR})
254+
get_target_property(OUT app LINK_LIBRARIES)
255+
message(STATUS ${OUT})

examples/arm/zephyr/Kconfig

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
# Copyright 2025 Arm Limited and/or its affiliates.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
source "Kconfig.zephyr"
8+
9+
menu "ExecuTorch Zephyr sample configuration"
10+
11+
config EXECUTORCH_METHOD_ALLOCATOR_POOL_SIZE
12+
int "Method allocator pool size in bytes"
13+
default 16384
14+
depends on EXECUTORCH
15+
help
16+
Size of the method allocator pool in bytes. This memory is used
17+
for allocating ExecuTorch method instances and their metadata.
18+
Default is 16KB which should be sufficient for most small models.
19+
Larger models may require more memory.
20+
21+
config EXECUTORCH_TEMP_ALLOCATOR_POOL_SIZE
22+
int "Temporary allocator pool size in bytes"
23+
default 2048
24+
depends on EXECUTORCH
25+
help
26+
Size of the temporary allocator pool in bytes. This memory is used
27+
for temporary allocations during model execution such as intermediate
28+
tensor calculations. Default is 2KB which should be sufficient for
29+
simple operations. Complex models may require more memory.
30+
31+
endmenu
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* Copyright 2025 Arm Limited and/or its affiliates.
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
/* Ensure ExecuTorch scratch buffers live in shared SRAM that the Ethos-U
7+
* DMA can access. The default board DTS routes Zephyr's general-purpose
8+
* SRAM to DTCM, which the NPU cannot reach. Override the choice so that
9+
* .data/.bss land in ISRAM (0x3100_0000) instead.
10+
*/
11+
/ {
12+
chosen {
13+
zephyr,sram = &isram;
14+
};
15+
};

examples/arm/zephyr/prj.conf

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
# Copyright 2025 Arm Limited and/or its affiliates.
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
# Enable ExecuTorch
8+
CONFIG_EXECUTORCH=y
9+
10+
# C++
11+
CONFIG_CPP=y
12+
CONFIG_STD_CPP17=y
13+
14+
# Needed as kernels/portable/cpu/op_allclose.cpp uses isfinite() instead of std::isfinite()
15+
# If you fully delegated your model to Ethos-U you could remove this and save some space
16+
CONFIG_NEWLIB_LIBC=y
17+
18+
# Config - increased for ExecuTorch memory requirements
19+
CONFIG_MAIN_STACK_SIZE=8192
20+
CONFIG_HEAP_MEM_POOL_SIZE=32768
21+
22+
# Logging
23+
CONFIG_REQUIRES_FLOAT_PRINTF=y
24+
25+
# Configuration for selective operator builds
26+
# Keep the portable operator registry enabled so selective builds can pull in
27+
# only the kernels required by the model (via EXECUTORCH_SELECT_OPS_MODEL).
28+
# Setting this means you will include all portable ops
29+
CONFIG_EXECUTORCH_BUILD_PORTABLE_OPS=n
30+
31+
# Enable the Zephyr Ethos-U driver so executorch_delegate_ethos_u can reserve
32+
# and use the hardware instance exposed by the board DTS.
33+
CONFIG_ETHOS_U=y
34+
35+
# Add model specific configs
36+
# The default 1 KB pool is too small even for the tiny sample model;
37+
# bump to 256 KB so method buffers and inputs fit during setup.
38+
CONFIG_EXECUTORCH_METHOD_ALLOCATOR_POOL_SIZE=262144
39+
# Ethos-U scratch memory requirements scale with the compiled network.
40+
CONFIG_EXECUTORCH_TEMP_ALLOCATOR_POOL_SIZE=1572864

0 commit comments

Comments
 (0)