Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,23 @@ announce_configured_options(BUILD_TESTING)
load_build_preset()
include(${PROJECT_SOURCE_DIR}/tools/cmake/preset/default.cmake)

# Keep bare-metal installs enabled only when ExecuTorch owns the top-level
# build. Standalone consumers (e.g., the runner) set
# EXECUTORCH_BAREMETAL_SKIP_INSTALL=ON but still add ExecuTorch as a subproject,
# which cannot satisfy our install() export dependencies until their own targets
# are configured.
if(DEFINED EXECUTORCH_BAREMETAL_SKIP_INSTALL
AND EXECUTORCH_BAREMETAL_SKIP_INSTALL
AND NOT (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
)
set(CMAKE_SKIP_INSTALL_RULES
ON
CACHE BOOL
"Skip install() rules when ExecuTorch is consumed as a subproject"
FORCE
)
endif()

# Enable ccache if available
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
Expand Down
27 changes: 24 additions & 3 deletions backends/arm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,20 @@ if(EXECUTORCH_BUILD_ARM_BAREMETAL OR EXECUTORCH_BUILD_ARM_ETHOSU_LINUX)

add_library(executorch_delegate_ethos_u STATIC ${_arm_backend_sources})
target_link_libraries(executorch_delegate_ethos_u PUBLIC executorch_core)
target_include_directories(
executorch_delegate_ethos_u PRIVATE ${_common_include_directories}
)

if(EXECUTORCH_BUILD_ARM_BAREMETAL)
target_sources(
executorch_delegate_ethos_u
PRIVATE ${EXECUTORCH_ROOT}/backends/arm/runtime/EthosUBackend_Cortex_M.cpp
)
set(DRIVER_ETHOSU_INCLUDE_DIR
set(_ethosu_core_driver_include
"${THIRD_PARTY_ROOT}/ethos-u-core-driver/include"
)
target_include_directories(
executorch_delegate_ethos_u PRIVATE ${DRIVER_ETHOSU_INCLUDE_DIR}
executorch_delegate_ethos_u PRIVATE ${_ethosu_core_driver_include}
)
target_link_libraries(executorch_delegate_ethos_u PUBLIC ethosu_core_driver)
elseif(EXECUTORCH_BUILD_ARM_ETHOSU_LINUX)
Expand Down Expand Up @@ -110,7 +113,25 @@ if(EXECUTORCH_BUILD_ARM_BAREMETAL OR EXECUTORCH_BUILD_ARM_ETHOSU_LINUX)
)
endif()

install(TARGETS executorch_delegate_ethos_u EXPORT ExecuTorchTargets)
if(NOT CMAKE_SKIP_INSTALL_RULES)
install(TARGETS executorch_delegate_ethos_u EXPORT ExecuTorchTargets)

if(TARGET ethosu_core_driver)
get_property(
_et_ethosu_core_driver_exported GLOBAL
PROPERTY ET_ETHOSU_CORE_DRIVER_EXPORTED
)
if(NOT _et_ethosu_core_driver_exported)
install(
TARGETS ethosu_core_driver
EXPORT ExecuTorchTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
set_property(GLOBAL PROPERTY ET_ETHOSU_CORE_DRIVER_EXPORTED TRUE)
endif()
endif()
endif()

endif()

Expand Down
60 changes: 60 additions & 0 deletions backends/arm/cmake/ArmEthosUSDK.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2026 Arm Limited and/or its affiliates.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

include_guard(GLOBAL)

function(arm_ethos_u_content_ready SDK_PATH OUT_VAR)
if(EXISTS "${SDK_PATH}/core_platform" AND EXISTS "${SDK_PATH}/core_software")
set(${OUT_VAR}
TRUE
PARENT_SCOPE
)
else()
set(${OUT_VAR}
FALSE
PARENT_SCOPE
)
endif()
endfunction()

function(arm_ethos_u_default_fetch SDK_PATH OUT_VAR)
arm_ethos_u_content_ready("${SDK_PATH}" _arm_ethos_ready)
if(_arm_ethos_ready)
set(${OUT_VAR}
OFF
PARENT_SCOPE
)
else()
set(${OUT_VAR}
ON
PARENT_SCOPE
)
endif()
endfunction()

function(arm_ensure_ethos_u_content SDK_PATH EXECUTORCH_ROOT FETCH_REQUESTED)
arm_ethos_u_content_ready("${SDK_PATH}" _arm_ethos_ready_before)

if(_arm_ethos_ready_before)
return()
endif()

if(NOT FETCH_REQUESTED)
message(
FATAL_ERROR
"No Ethos-U content found at ${SDK_PATH}. Run examples/arm/setup.sh or enable FETCH_ETHOS_U_CONTENT=ON."
)
endif()

fetch_ethos_u_content(${SDK_PATH} ${EXECUTORCH_ROOT})

arm_ethos_u_content_ready("${SDK_PATH}" _arm_ethos_ready_after)
if(NOT _arm_ethos_ready_after)
message(
FATAL_ERROR
"Failed to fetch Ethos-U content into ${SDK_PATH}. Inspect the logs above."
)
endif()
endfunction()
69 changes: 69 additions & 0 deletions backends/arm/cmake/ArmRunnerUtils.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright 2026 Arm Limited and/or its affiliates.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

include_guard(GLOBAL)

# Helper routines shared by the standalone runner and any superbuild that reuses
# the runner targets.

function(arm_runner_require_baremetal_targets)
if(NOT TARGET extension_runner_util)
message(
FATAL_ERROR
"extension_runner_util target missing. Configure ExecuTorch (or the standalone runner) with EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON."
)
endif()

if(NOT TARGET quantized_ops_lib OR NOT TARGET quantized_kernels)
message(
FATAL_ERROR
"quantized kernels not found. Ensure EXECUTORCH_BUILD_KERNELS_QUANTIZED=ON when configuring ExecuTorch."
)
endif()

if(NOT TARGET cortex_m_ops_lib OR NOT TARGET cortex_m_kernels)
message(
FATAL_ERROR
"cortex_m backend not found. Ensure EXECUTORCH_BUILD_CORTEX_M=ON when configuring ExecuTorch."
)
endif()
endfunction()

# Ensure a runner target emits its binary to a predictable location. Uses
# FALLBACK_DIR when TARGET_NAME has no runtime output directory set, and also
# fills per-configuration runtime output directories for multi-config generators
# when they are unset.
function(arm_runner_configure_runtime_output TARGET_NAME FALLBACK_DIR)
if(NOT TARGET ${TARGET_NAME})
return()
endif()

get_target_property(_base_runtime_dir ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY)
if(NOT _base_runtime_dir
OR _base_runtime_dir STREQUAL "_base_runtime_dir-NOTFOUND"
OR "${_base_runtime_dir}" STREQUAL ""
)
set_target_properties(
${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${FALLBACK_DIR}"
)
set(_base_runtime_dir "${FALLBACK_DIR}")
endif()

if(CMAKE_CONFIGURATION_TYPES)
foreach(_cfg ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${_cfg} _cfg_upper)
set(_cfg_prop "RUNTIME_OUTPUT_DIRECTORY_${_cfg_upper}")
get_target_property(_cfg_dir ${TARGET_NAME} ${_cfg_prop})
if(NOT _cfg_dir
OR _cfg_dir STREQUAL "_cfg_dir-NOTFOUND"
OR "${_cfg_dir}" STREQUAL ""
)
set_target_properties(
${TARGET_NAME} PROPERTIES ${_cfg_prop} "${_base_runtime_dir}/${_cfg}"
)
endif()
endforeach()
endif()
endfunction()
67 changes: 43 additions & 24 deletions backends/arm/scripts/build_executor_runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ set -eu
script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)
et_root_dir=$(cd ${script_dir}/../../.. && pwd)
et_root_dir=$(realpath ${et_root_dir})
runner_source_dir=${et_root_dir}/examples/arm/executor_runner/standalone
runner_source_dir=$(realpath ${runner_source_dir})
preset_file=${et_root_dir}/tools/cmake/preset/arm_baremetal.cmake
toolchain=arm-none-eabi-gcc
setup_path_script=${et_root_dir}/examples/arm/arm-scratch/setup_path.sh
_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools."
Expand Down Expand Up @@ -101,6 +104,9 @@ toolchain_cmake=$(realpath ${toolchain_cmake})

source ${setup_path_script}

[[ -f ${preset_file} ]] \
|| { echo "Missing ${preset_file}. ${_setup_msg}"; exit 1; }

if [[ ${pte_file} == "semihosting" ]]; then
pte_data="-DSEMIHOSTING=ON"
else
Expand All @@ -122,13 +128,13 @@ else
fi
fi
ethosu_tools_dir=$(realpath ${ethosu_tools_dir})
ethos_u_root_dir="$ethosu_tools_dir/ethos-u"
ethos_u_root_dir="${ethosu_tools_dir}/ethos-u"
mkdir -p "${ethos_u_root_dir}"
ethosu_tools_dir=$(realpath ${ethos_u_root_dir})

et_build_dir=${et_build_root}/cmake-out
mkdir -p ${et_build_dir}
et_build_dir=$(realpath ${et_build_dir})
ethos_u_root_dir=$(realpath ${ethos_u_root_dir})
cmsis_nn_local_path=""
if [[ -d "${ethos_u_root_dir}/core_software/cmsis-nn" ]]; then
cmsis_nn_local_path=$(realpath "${ethos_u_root_dir}/core_software/cmsis-nn")
fi

if [[ ${system_config} == "" ]]
then
Expand Down Expand Up @@ -160,34 +166,47 @@ echo "--------------------------------------------------------------------------
echo "Build Arm ${toolchain/-gcc/} executor_runner for ${target} PTE: ${pte_file} using ${system_config} ${memory_mode} ${extra_build_flags} to '${output_folder}'"
echo "--------------------------------------------------------------------------------"

cd ${et_root_dir}/examples/arm/executor_runner

if [ "$bundleio" = true ] ; then
build_bundleio_flags=" -DET_BUNDLE_IO=ON "
candidate_build_dir="${et_build_root}/cmake-out"
if [[ -d "${candidate_build_dir}" ]]; then
candidate_build_dir=$(realpath "${candidate_build_dir}")
build_bundleio_flags+=" -DET_BUILD_DIR_PATH=${candidate_build_dir} "
fi
if [[ -n "${BUNDLED_PROGRAM_LIBRARY_DIR:-}" ]]; then
build_bundleio_flags+=" -DBUNDLED_PROGRAM_LIBRARY_DIR=${BUNDLED_PROGRAM_LIBRARY_DIR} "
fi
fi

if [ "$build_with_etdump" = true ] ; then
build_with_etdump_flags=" -DEXECUTORCH_ENABLE_EVENT_TRACER=ON -DET_DUMP_INTERMEDIATE_OUTPUTS=ON "
fi
devtools_flags=""
if [ "$bundleio" = true ] || [ "$build_with_etdump" = true ] ; then
devtools_flags=" -DEXECUTORCH_BUILD_DEVTOOLS=ON "
fi

echo "Building with BundleIO/etdump/extra flags: ${build_bundleio_flags} ${build_with_etdump_flags} ${extra_build_flags}"
echo "Building with BundleIO/etdump/extra flags: ${build_bundleio_flags} ${build_with_etdump_flags} ${devtools_flags} ${extra_build_flags}"
cmake \
-DCMAKE_BUILD_TYPE=${build_type} \
-DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \
-DTARGET_CPU=${target_cpu} \
-DET_DIR_PATH:PATH=${et_root_dir} \
-DET_BUILD_DIR_PATH:PATH=${et_build_dir} \
-DETHOS_SDK_PATH:PATH=${ethos_u_root_dir} \
-DETHOSU_TARGET_NPU_CONFIG=${target} \
${pte_data} \
${build_bundleio_flags} \
${build_with_etdump_flags} \
-DPYTHON_EXECUTABLE=$(which python3) \
-DSYSTEM_CONFIG=${system_config} \
-DMEMORY_MODE=${memory_mode} \
-S ${runner_source_dir} \
-B ${output_folder} \
-DEXECUTORCH_ROOT=${et_root_dir} \
-DCMAKE_BUILD_TYPE=${build_type} \
-DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \
-DTARGET_CPU=${target_cpu} \
-DETHOSU_TARGET_NPU_CONFIG=${target} \
-DEXECUTORCH_BUILD_PRESET_FILE=${preset_file} \
-DEXECUTORCH_BAREMETAL_SKIP_INSTALL=OFF \
${pte_data} \
${build_bundleio_flags} \
${build_with_etdump_flags} \
${devtools_flags} \
-DSYSTEM_CONFIG=${system_config} \
-DMEMORY_MODE=${memory_mode} \
-DEXECUTORCH_SELECT_OPS_LIST="${select_ops_list}" \
${extra_build_flags} \
-B ${output_folder}
-DETHOS_SDK_PATH:PATH=${ethos_u_root_dir} \
${cmsis_nn_local_path:+-DCMSIS_NN_LOCAL_PATH:PATH=${cmsis_nn_local_path}} \
${extra_build_flags}

echo "[${BASH_SOURCE[0]}] Configured CMAKE"

Expand Down
3 changes: 2 additions & 1 deletion backends/arm/scripts/build_executorch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ cmake_args=(
-DCMAKE_BUILD_TYPE=${build_type}
-DEXECUTORCH_BUILD_DEVTOOLS=${build_devtools}
-DEXECUTORCH_BUILD_ARM_ETDUMP=${build_with_etdump}
-DEXECUTORCH_BAREMETAL_SKIP_INSTALL=OFF
)

if [[ ${is_linux_musl} -eq 1 ]]; then
Expand All @@ -108,7 +109,7 @@ parallel_jobs="$(get_parallel_jobs)"
if [[ ${is_linux_musl} -eq 1 ]]; then
cmake --build ${et_build_dir} -j"${parallel_jobs}" --target executorch_delegate_ethos_u executor_runner --config ${build_type} --
else
cmake --build ${et_build_dir} -j"${parallel_jobs}" --target install --config ${build_type} --
cmake --build ${et_build_dir} -j"${parallel_jobs}" --config ${build_type}
fi

set +x
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The Arm® Ethos™-U backend targets Edge/IoT-type AI use-cases by enabli
[Arm® Ethos™-U55 NPU](https://www.arm.com/products/silicon-ip-cpu/ethos/ethos-u55), [Arm® Ethos™-U65 NPU](https://www.arm.com/products/silicon-ip-cpu/ethos/ethos-u65), and
[Arm® Ethos™-U85 NPU](https://www.arm.com/products/silicon-ip-cpu/ethos/ethos-u85), leveraging [TOSA](https://www.mlplatform.org/tosa/) and the
[ethos-u-vela](https://pypi.org/project/ethos-u-vela/) graph compiler. This document is a technical reference for using the Ethos-U backend, for a top level view with code examples
please refer to the [Arm Ethos-U Backend Tutorial](https://docs.pytorch.org/executorch/stable/tutorial-arm-ethos-u.html).
please refer to the [Arm Ethos-U Backend Tutorial](tutorials/ethos-u-getting-started.md).

## Features

Expand All @@ -27,7 +27,7 @@ For the AOT flow, compilation of a model to `.pte` format using the Ethos-U back
- [TOSA Serialization Library](https://www.mlplatform.org/tosa/software.html) for serializing the Exir IR graph into TOSA IR.
- [Ethos-U Vela graph compiler](https://pypi.org/project/ethos-u-vela/) for compiling TOSA flatbuffers into an Ethos-U command stream.

And for building and running the example application available in `examples/arm/executor_runner/`:
And for building and running the example application available in `examples/arm/executor_runner/` through the standalone CMake entry point:
- [Arm GNU Toolchain](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) for cross compilation.
- [Arm® Corstone™ SSE-300 FVP](https://developer.arm.com/documentation/100966/1128/Arm--Corstone-SSE-300-FVP) for testing on a Arm® Cortex®-M55+Ethos-U55 reference design.
- [Arm® Corstone™ SSE-320 FVP](https://developer.arm.com/documentation/109760/0000/SSE-320-FVP) for testing on a Arm® Cortex®-M85+Ethos-U85 reference design.
Expand Down Expand Up @@ -55,7 +55,7 @@ For more information on quantization, see [Quantization](arm-ethos-u-quantizatio

## Runtime Integration

An example runtime application is available in [examples/arm/executor_runner](https://github.com/pytorch/executorch/blob/main/examples/arm/executor_runner/), and the steps requried for building and deploying it on a FVP it is explained in the previously mentioned [Arm Ethos-U Backend Tutorial](https://docs.pytorch.org/executorch/stable/tutorial-arm-ethos-u.html).
An example runtime application is available in [examples/arm/executor_runner](https://github.com/pytorch/executorch/blob/main/examples/arm/executor_runner/), with a standalone CMake entry point in `examples/arm/executor_runner/standalone`. The steps required for building and deploying it on an FVP are explained in the previously mentioned [Arm Ethos-U Backend Tutorial](tutorials/ethos-u-getting-started.md).
The example application is recommended to use for testing basic functionality of your lowered models, as well as a starting point for developing runtime integrations for your own targets.
For an in-depth explanation of the architecture of the executor_runner and the steps required for doing such an integration, please refer to [Ethos-U porting guide](https://github.com/pytorch/executorch/blob/main/examples/arm/ethos-u-porting-guide.md).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,35 +76,28 @@ To produce a pte file equivalent to the one above, run

### Runtime:

After the AOT compilation flow is done, the runtime can be cross compiled and linked to the produced `.pte`-file using the Arm cross-compilation toolchain. This is done in two steps:
After the AOT compilation flow is done, the runtime can be cross compiled and linked to the produced `.pte`-file using the Arm cross-compilation toolchain. Configure the standalone Arm executor runner CMake project to pull in the ExecuTorch build graph, link the Ethos-U delegate, and generate kernel bindings for any non-delegated ops. This produces the `arm_executor_runner` program that will run on target.

First, build and install the ExecuTorch libraries and EthosUDelegate:
```
# In ExecuTorch top-level, with sourced setup_path.sh
cmake -DCMAKE_BUILD_TYPE=Release --preset arm-baremetal -B cmake-out-arm .
cmake --build cmake-out-arm --target install -j$(nproc)
```
Second, build and link the `arm_executor_runner` and generate kernel bindings for any non delegated ops. This is the actual program that will run on target.

```
# In ExecuTorch top-level, with sourced setup_path.sh
cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake \
cmake -S examples/arm/executor_runner/standalone \
-B ethos_u_minimal_example \
-DEXECUTORCH_ROOT=$(pwd) \
-DCMAKE_TOOLCHAIN_FILE=$(pwd)/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DET_PTE_FILE_PATH=ethos_u_minimal_example.pte \
-DTARGET_CPU=cortex-m55 \
-DETHOSU_TARGET_NPU_CONFIG=ethos-u55-128 \
-DMEMORY_MODE=Shared_Sram \
-DSYSTEM_CONFIG=Ethos_U55_High_End_Embedded \
-Bethos_u_minimal_example \
examples/arm/executor_runner
-DSYSTEM_CONFIG=Ethos_U55_High_End_Embedded
cmake --build ethos_u_minimal_example -j$(nproc) -- arm_executor_runner
```

```{tip}
For a quick start, you can use the script `backends/arm/scripts/build_executor_runner.sh` to build the runner.
For a quick start, you can use the script `backends/arm/scripts/build_executor_runner.sh` to configure and build the standalone runner.
To build a runner equivalent to the one above, run
`./backends/arm/scripts/build_executor_runner.sh --pte=ethos_u_minimal_example.pte`
````
```

The block diagram below shows, at the high level, how the various build artifacts are generated and are linked together to generate the final bare-metal executable.

Expand Down
Loading
Loading