Skip to content

Commit 8b2d288

Browse files
Arm backend: Add CMSIS Pack all-ops test and fix pack build infrastructure (#21709)
Reworks the CMSIS Pack build infrastructure for the 1.4 operator surface and adds a consumer-side all-ops test that builds and runs every operator the pack ships. ### Review order Start with `scripts/`. `generate_register_all_kernels.py` is rewritten to emit registrations from the NativeFunctions yaml rather than the previous hand-maintained mapping, and operator discovery moves into the new `op_guards.py` shared by the registration and component generators. `copy_sources.sh` and `test/validate_pack.py` then hard-fail on a pack missing the build-generated headers rather than producing a quietly incomplete archive. `templates/PyTorch.ExecuTorch.pdsc.tpl` gains the Extension Tensor component and per-op Cortex-M components. Then `test/all_ops/`, which is the bulk of the diff and independent of the above. `op_recipes.py` defines one recipe per operator; `generate_test_models.py` turns each into a self-contained `.pte` carrying its inputs, expected outputs and tolerances as constant methods; `gen_cproject.py` generates a consumer project selecting every operator component; `main.cpp` runs each model on target and prints a per-op cycle table, a memory high-water report and a `SUMMARY <pass>/<total>` line. `run.sh` drives the flow. Host-side unit tests accompany each generator. Coverage is two-tier, documented in `SKIPPED_OPS.md`: every operator is build/link covered with no exemptions, and those not value-checked on device each carry a machine-enforced reason (nondeterministic RNG, uninitialized `empty`, data-dependent output shape), so a silent coverage gap fails the test suite. The last commit is a one-line, independent fix: the generated PDSC `<url>` omitted the tag's leading `v`, so `releases/download/1.4.0/` 404s where `releases/download/v1.4.0/` serves the asset. ### Validation Built from the 1.4.0 release sources with these scripts, the resulting pack validates structurally, and a consumer project selecting all 198 operator components compiles and links clean (368 compile units, `1 succeeded, 0 failed`) for Corstone-315 with arm-none-eabi-gcc 14.3.1 and CMSIS-Toolbox 2.14.1. Booting that image on `FVP_Corstone_SSE-315` gives: ``` Test_result: SUMMARY 167/167 PASS MemReport: method=84292 temp=0 meta=88 metatmp=0 ``` The test targets two Cortex-M85 MPS4 subsystems: Corstone-315 (SSE-315) for the CPU path and Corstone-320 (SSE-320) with an Ethos-U85 for a delegated variant. cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani --------- Signed-off-by: Matthias Hertel <matthias.hertel@arm.com>
1 parent 076774b commit 8b2d288

33 files changed

Lines changed: 4941 additions & 1166 deletions

.github/workflows/build-cmsis-pack.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ on:
2222
paths:
2323
- .github/workflows/build-cmsis-pack.yml
2424
- backends/arm/cmsis_pack/**
25-
- backends/arm/cmsis_pack/scripts/**
2625
- backends/arm/runtime/**
2726
- backends/cortex_m/**
2827
- kernels/portable/**
@@ -33,7 +32,6 @@ on:
3332
paths:
3433
- .github/workflows/build-cmsis-pack.yml
3534
- backends/arm/cmsis_pack/**
36-
- backends/arm/cmsis_pack/scripts/**
3735
workflow_dispatch:
3836
inputs:
3937
version_override:
@@ -80,7 +78,9 @@ jobs:
8078
# Stage 1: Build core ExecuTorch with arm-none-eabi-gcc
8179
# This generates required headers (flatbuffers, schema)
8280
backends/arm/scripts/build_executorch.sh
83-
CMAKE_BUILD_DIR="$(pwd)/cmake-out-arm"
81+
# Must match build_executorch.sh's output dir (et_build_root/cmake-out);
82+
# copy_sources.sh hard-fails if the generated schema headers are absent.
83+
CMAKE_BUILD_DIR="$(pwd)/arm_test/cmake-out"
8484
echo "::endgroup::"
8585
8686
echo "::group::Determine pack version"

backends/arm/cmsis_pack/contributions/add/Documentation/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ This pack provides:
2828
- component: Machine Learning:ExecuTorch:Runtime
2929
- component: Machine Learning:ExecuTorch:Kernel Utils
3030

31-
# Backend (choose one or more)
32-
- component: Machine Learning:ExecuTorch:Backend::EthosU
31+
# Backend (choose one or more). CMSIS component IDs use a single
32+
# colon between Cclass / Cgroup / Csub, with a space (not "::")
33+
# inside the Csub name.
34+
- component: Machine Learning:ExecuTorch:Backend EthosU
3335
# or
34-
- component: Machine Learning:ExecuTorch:Backend::CortexM
36+
- component: Machine Learning:ExecuTorch:Backend CortexM
3537
```
3638
3739
3. Include ExecuTorch headers in your code:

backends/arm/cmsis_pack/scripts/build_pack.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,21 @@ cd "$PACK_BUILD"
107107
if command -v zip &> /dev/null; then
108108
zip -r "$PACK_FILE" . -x "*.DS_Store" -x ".git*" -x "*/generated/*" -x "*.py"
109109
else
110-
python3 -c "
111-
import zipfile, os
112-
with zipfile.ZipFile('$PACK_FILE', 'w', zipfile.ZIP_DEFLATED) as zf:
110+
# Pass $PACK_FILE as sys.argv[1] so the path is safe against
111+
# shell-special characters (single quotes in particular).
112+
python3 - "$PACK_FILE" <<'PYEOF'
113+
import sys, zipfile, os
114+
pack_file = sys.argv[1]
115+
with zipfile.ZipFile(pack_file, 'w', zipfile.ZIP_DEFLATED) as zf:
113116
for root, dirs, files in os.walk('.'):
114117
dirs[:] = [d for d in dirs if not d.startswith('.') and d != 'generated']
115118
for f in files:
116119
if f.startswith('.') or f == '.DS_Store' or f.endswith('.py'):
117120
continue
118121
p = os.path.join(root, f)
119122
zf.write(p, os.path.relpath(p, '.'))
120-
print(f'Created: $PACK_FILE')
121-
"
123+
print(f'Created: {pack_file}')
124+
PYEOF
122125
fi
123126

124127
echo ""

backends/arm/cmsis_pack/scripts/copy_sources.sh

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# Usage:
1515
# ./copy_sources.sh --executorch-root <path> --build-dir <path> \
1616
# --pack-staging <path>
17-
set -e
17+
set -euo pipefail
1818

1919
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
2020
PACK_DIR="$(cd "$SCRIPT_DIR/../../cmsis_pack" && pwd)"
@@ -115,7 +115,7 @@ cp -r "${PACK_SRC}/src/kernels" "${PACK_SRC}/include/executorch/"
115115

116116
echo " Copying extension sources..."
117117
mkdir -p "${PACK_SRC}/src/extension"
118-
for d in data_loader memory_allocator runner_util; do
118+
for d in data_loader memory_allocator runner_util tensor; do
119119
if [[ -d "${EXECUTORCH_ROOT}/extension/$d" ]]; then
120120
cp -r "${EXECUTORCH_ROOT}/extension/$d" "${PACK_SRC}/src/extension/"
121121
fi
@@ -138,6 +138,18 @@ for candidate in \
138138
break
139139
fi
140140
done
141+
# A pack without the generated flatbuffers schema headers compiles nothing:
142+
# every consumer fails at executorch/schema/program_generated.h. Fail here
143+
# rather than shipping a broken archive.
144+
for required in program_generated.h scalar_type_generated.h; do
145+
if [[ ! -f "${PACK_SRC}/src/schema/${required}" ]]; then
146+
echo "ERROR: ${required} not found in the CMake build tree." >&2
147+
echo " Looked in: ${BUILD_DIR}/schema/include/executorch/schema" >&2
148+
echo " Run the ExecuTorch CMake configure+build first so BUILD_DIR" >&2
149+
echo " contains the generated schema headers (see build_pack.sh -h)." >&2
150+
exit 1
151+
fi
152+
done
141153
cp -r "${PACK_SRC}/src/schema" "${PACK_SRC}/include/executorch/"
142154

143155
echo " Copying generated flatbuffers headers..."
@@ -150,14 +162,27 @@ for candidate in \
150162
break
151163
fi
152164
done
165+
# Same rule as the schema headers: the pack bundles flatbuffers/, and the
166+
# runtime does not compile without it. Refuse to produce a pack missing it.
167+
if [[ ! -f "${PACK_SRC}/include/flatbuffers/flatbuffers.h" ]]; then
168+
echo "ERROR: flatbuffers headers not found in the CMake build tree." >&2
169+
echo " Looked in: ${BUILD_DIR}/third-party/{flatbuffers,flatc_ep}/include" >&2
170+
echo " Run the ExecuTorch CMake configure+build first so BUILD_DIR" >&2
171+
echo " contains the flatc external-project headers." >&2
172+
exit 1
173+
fi
153174

154-
# Flatbuffers headers are redistributed inside the pack; ship the
155-
# upstream Apache-2.0 LICENSE alongside per its terms.
156-
if [[ -f "${EXECUTORCH_ROOT}/third-party/flatbuffers/LICENSE" ]] \
157-
&& [[ -d "${PACK_SRC}/include/flatbuffers" ]]; then
158-
cp "${EXECUTORCH_ROOT}/third-party/flatbuffers/LICENSE" \
159-
"${PACK_SRC}/include/flatbuffers/LICENSE"
175+
# Flatbuffers headers are redistributed inside the pack, so shipping the
176+
# upstream Apache-2.0 LICENSE alongside them is a condition of that
177+
# redistribution -- a pack without it must not be published.
178+
if [[ ! -f "${EXECUTORCH_ROOT}/third-party/flatbuffers/LICENSE" ]]; then
179+
echo "ERROR: third-party/flatbuffers/LICENSE not found in the source tree." >&2
180+
echo " The pack redistributes the flatbuffers headers and must ship" >&2
181+
echo " their licence. Run: git submodule update --init third-party/flatbuffers" >&2
182+
exit 1
160183
fi
184+
cp "${EXECUTORCH_ROOT}/third-party/flatbuffers/LICENSE" \
185+
"${PACK_SRC}/include/flatbuffers/LICENSE"
161186

162187
echo " Creating c10 and torch include paths..."
163188
C10_DIR="${PACK_SRC}/src/runtime/core/portable_type/c10/c10"

0 commit comments

Comments
 (0)