Skip to content

Commit 043c65b

Browse files
authored
Test optimized ESP-NN kernels on the S3 emulator (#24244)
### Summary Espressif CI forces ESP-NN's ANSI C kernels because the pinned emulator predates S3 SIMD support. Upgrade esp-emulator to 0.51.0 and run the existing BundleIO suite in separate optimized and ANSI jobs. Each job verifies its SDK configuration and retains the bundled fixtures, resolved component versions, SDK configuration, and logs. Document ESP-NN's automatic target selection and keep tool-version pins in `setup.sh`. ### Test plan Ran both complete CI configurations locally with ESP-IDF v6.1 and ESP-NN 1.4.1: ```bash ESPRESSIF_NN_KERNELS=optimized bash .ci/scripts/test_espressif.sh ESPRESSIF_NN_KERNELS=ansi bash .ci/scripts/test_espressif.sh ``` Each passed all 16 delegate fixtures and three smoke inferences. The bundles were byte-identical between runs, with existing tolerances unchanged. The optimized SDK configuration and link map confirmed S3 assembly with `NN_SKIP_NUDGE` disabled. ShellCheck, Bash syntax checks, scoped lintrunner, workflow parsing, invalid-kernel-selection rejection, and `git diff --check` passed. The pinned installer checksum was verified against the new emulator release. Authored with AI assistance using Codex.
1 parent d4bf403 commit 043c65b

5 files changed

Lines changed: 63 additions & 32 deletions

File tree

‎.ci/scripts/test_espressif.sh‎

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ set -euo pipefail
99

1010
et_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
1111
build_dir="${ESPRESSIF_BUILD_DIR:-${et_root}/cmake-out-esp-emulator}"
12+
espnn_kernels="${ESPRESSIF_NN_KERNELS:-optimized}"
13+
case "${espnn_kernels}" in
14+
optimized) espnn_config=CONFIG_NN_OPTIMIZED ;;
15+
ansi) espnn_config=CONFIG_NN_ANSI_C ;;
16+
*) echo "ESPRESSIF_NN_KERNELS must be optimized or ansi" >&2; exit 1 ;;
17+
esac
1218
export ESPRESSIF_TOOLS_DIR="${ESPRESSIF_TOOLS_DIR:-${RUNNER_TEMP:-/tmp}/executorch-espressif}"
1319
mkdir -p "${build_dir}"
1420
build_dir=$(cd "${build_dir}" && pwd)
@@ -18,6 +24,11 @@ collect_artifacts() {
1824
if [[ -n "${RUNNER_ARTIFACT_DIR:-}" ]]; then
1925
mkdir -p "${RUNNER_ARTIFACT_DIR}/esp32s3"
2026
for file in "${build_dir}"/*.log "${build_dir}"/*.bpte \
27+
"${build_dir}"/espnn-*-sdkconfig \
28+
"${build_dir}/espnn-tests"/*.bpte \
29+
"${build_dir}/espnn-tests/manifest.json" \
30+
"${build_dir}/espnn-tests/operators.txt" \
31+
"${et_root}/examples/espressif/project/dependencies.lock" \
2132
"${build_dir}/firmware/merged-binary.bin" \
2233
"${build_dir}/firmware/executorch_esp_runner.elf"; do
2334
if [[ -f "${file}" ]]; then
@@ -80,9 +91,10 @@ python examples/espressif/test_emulator.py "${build_dir}/emulator.log"
8091

8192
# ESP-NN backend: run every exported program through the ExecuTorch runtime
8293
# and the ESP-NN delegate, and check it against the bundled host reference.
83-
# The emulator does not implement the ESP32-S3 SIMD instructions, so ESP-NN is
84-
# built with its ANSI C kernels.
85-
printf 'CONFIG_NN_ANSI_C=y\n' > "${build_dir}/espnn-emulator.defaults"
94+
espnn_firmware_dir="${build_dir}/espnn-${espnn_kernels}-firmware"
95+
espnn_sdkconfig="${build_dir}/espnn-${espnn_kernels}-sdkconfig"
96+
espnn_defaults="${build_dir}/espnn-${espnn_kernels}.defaults"
97+
printf '%s=y\n' "${espnn_config}" > "${espnn_defaults}"
8698
# Runs a command with its output in a log, and shows the log's tail on failure.
8799
logged() {
88100
local log="${build_dir}/$1"
@@ -94,26 +106,31 @@ logged() {
94106
fi
95107
}
96108
while read -r -u 3 name atol rtol; do
97-
logged "espnn-${name}-configure.log" \
98-
idf.py -C examples/espressif/project -B "${build_dir}/espnn-firmware" \
109+
espnn_log_prefix="espnn-${espnn_kernels}-${name}"
110+
logged "${espnn_log_prefix}-configure.log" \
111+
idf.py -C examples/espressif/project -B "${espnn_firmware_dir}" \
99112
-DIDF_TARGET=esp32s3 \
100-
-DSDKCONFIG="${build_dir}/espnn-sdkconfig" \
101-
"-DSDKCONFIG_DEFAULTS=sdkconfig.defaults;${build_dir}/espnn-emulator.defaults" \
113+
-DSDKCONFIG="${espnn_sdkconfig}" \
114+
"-DSDKCONFIG_DEFAULTS=sdkconfig.defaults;${espnn_defaults}" \
102115
-DET_ESPNN_BACKEND=ON \
103116
-DET_BUILD_DIR_PATH="${build_dir}/runtime" \
104117
-DET_PTE_FILE_PATH="${build_dir}/espnn-tests/${name}.bpte" \
105118
-DET_BUNDLE_IO=ON -DET_NUM_INFERENCES=1 \
106119
-DET_ATOL="${atol}" -DET_RTOL="${rtol}" reconfigure
107-
logged "espnn-${name}-build.log" cmake --build "${build_dir}/espnn-firmware"
108-
logged "espnn-${name}-merge.log" \
109-
idf.py -C examples/espressif/project -B "${build_dir}/espnn-firmware" merge-bin
110-
logged "espnn-${name}-emulator.log" \
120+
if ! grep -qx "${espnn_config}=y" "${espnn_sdkconfig}"; then
121+
echo "Expected ${espnn_config}=y in ${espnn_sdkconfig}" >&2
122+
exit 1
123+
fi
124+
logged "${espnn_log_prefix}-build.log" cmake --build "${espnn_firmware_dir}"
125+
logged "${espnn_log_prefix}-merge.log" \
126+
idf.py -C examples/espressif/project -B "${espnn_firmware_dir}" merge-bin
127+
logged "${espnn_log_prefix}-emulator.log" \
111128
timeout 90s esp-emu --chip esp32s3 \
112-
--firmware "${build_dir}/espnn-firmware/merged-binary.bin" \
113-
--elf "${build_dir}/espnn-firmware/executorch_esp_runner.elf" \
129+
--firmware "${espnn_firmware_dir}/merged-binary.bin" \
130+
--elf "${espnn_firmware_dir}/executorch_esp_runner.elf" \
114131
--net user --psram-size 8M --timeout 60s --exit-on 'Program complete.'
115-
echo -n "${name}: "
116-
python examples/espressif/test_emulator.py "${build_dir}/espnn-${name}-emulator.log"
132+
echo -n "${espnn_kernels}/${name}: "
133+
python examples/espressif/test_emulator.py "${build_dir}/${espnn_log_prefix}-emulator.log"
117134
done 3< <(python -c '
118135
import json, sys
119136
for entry in json.load(open(sys.argv[1])):

‎.github/workflows/test-espressif.yml‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ jobs:
2727
uses: ./.github/workflows/_docker-image.yml
2828

2929
test-esp32s3:
30+
name: ESP32-S3 (${{ matrix.kernels }})
3031
needs: docker-image
32+
strategy:
33+
fail-fast: false
34+
matrix:
35+
kernels: [optimized, ansi]
3136
uses: pytorch/test-infra/.github/workflows/linux_job_v3.yml@main
3237
permissions:
3338
id-token: write
@@ -38,11 +43,11 @@ jobs:
3843
submodules: recursive
3944
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
4045
timeout: 45
41-
upload-artifact: test-report-esp32s3
46+
upload-artifact: test-report-esp32s3-${{ matrix.kernels }}
4247
script: |
4348
set -euo pipefail
4449
CONDA_ENV=$(conda env list --json | jq -r '.envs | .[-1]')
4550
conda activate "${CONDA_ENV}"
4651
source .ci/scripts/utils.sh
4752
install_executorch --use-pt-pinned-commit --minimal
48-
bash .ci/scripts/test_espressif.sh
53+
ESPRESSIF_NN_KERNELS="${{ matrix.kernels }}" bash .ci/scripts/test_espressif.sh

‎backends/espressif/README.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Calibrate on a few hundred real samples; random data gives useless scales.
102102

103103
## Running on the ESP32-S3
104104

105-
You need ESP-IDF (CI uses v6.1) and an activated ESP-IDF shell.
105+
You need ESP-IDF and an activated ESP-IDF shell.
106106
[`examples/espressif/setup.sh`](../../examples/espressif/setup.sh) installs a
107107
matching ESP-IDF and the emulator.
108108

@@ -160,6 +160,10 @@ against the ExecuTorch targets that `executor_runner` imports, and registers
160160
`EspNNBackend` at startup. It defines no platform layer; the runner's
161161
`esp_pal.cpp` provides it.
162162

163+
ESP-NN defaults to `CONFIG_NN_OPTIMIZED=y` and selects its implementation from
164+
ESP-IDF's `IDF_TARGET`. For `esp32s3`, this enables the S3 assembly kernels.
165+
`CONFIG_NN_ANSI_C=y` selects reference C kernels for verification and debugging.
166+
163167
For a BundleIO program (`.bpte`), add `-DET_BUNDLE_IO=ON` and the tolerances
164168
`-DET_ATOL=... -DET_RTOL=...`. The runner then checks the outputs against the
165169
bundled reference and logs `Test_result: PASS` or `FAIL`.
@@ -197,8 +201,10 @@ BundleIO program with the host reference's outputs. CI builds the runner with
197201
`-DET_ESPNN_BACKEND=ON` for each program and runs it in `esp-emu`. Fully
198202
delegated programs must match to float precision, which means bit-exact int8
199203
results. Programs with CPU regions get a tolerance for the portable kernels'
200-
float rounding. The emulator does not implement the S3 SIMD instructions, so
201-
this build uses ESP-NN's ANSI C kernels (`CONFIG_NN_ANSI_C=y`).
204+
float rounding. Separate CI jobs run ESP-NN's optimized S3 kernels and its
205+
ANSI C reference kernels against the same bundled outputs. Both jobs target
206+
ESP32-S3. Logs include the kernel configuration in their filenames; artifacts
207+
retain the bundled fixtures, SDK configuration, and resolved component versions.
202208

203209
The code follows the ExecuTorch coding style and passes the repository's
204210
`lintrunner` checks:

‎examples/espressif/README.md‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,13 @@ bash examples/espressif/setup.sh
202202
source ~/.cache/executorch-espressif/setup_path.sh
203203
```
204204

205-
The installer uses ESP-IDF **v6.1** and esp-emulator **0.48.0**, verifying the
206-
emulator installer's pinned SHA-256 checksum before running it. ESP-IDF's Python
207-
dependencies are installed into your active environment, so the SDK and
208-
ExecuTorch share the same Python. The generated `setup_path.sh` adds the installed
209-
tools to `PATH` and selects the ESP32-S3 target. In a new shell, activate the same
210-
Python environment and source this file. Installation only needs to be done once.
205+
The ESP-IDF and esp-emulator versions are pinned in [setup.sh](setup.sh). The
206+
installer verifies the emulator installer's pinned SHA-256 checksum before
207+
running it. ESP-IDF's Python dependencies are installed into your active
208+
environment, so the SDK and ExecuTorch share the same Python. The generated
209+
`setup_path.sh` adds the installed tools to `PATH` and selects the ESP32-S3 target.
210+
In a new shell, activate the same Python environment and source this file.
211+
Installation only needs to be done once.
211212

212213
The default install includes ESP-IDF's standard ESP32-S3 development tools,
213214
including GDB, OpenOCD, and the ULP toolchains. OpenOCD requires your platform's
@@ -225,7 +226,7 @@ the tools. Rerun setup without `--minimal` to add the full development toolset.
225226

226227
Set `ESPRESSIF_TOOLS_DIR` to choose another installation directory. The installer
227228
prints the corresponding activation command. It also accepts `IDF_PATH` and
228-
`IDF_TOOLS_PATH` for an existing ESP-IDF v6.1 installation. The setup script checks
229+
`IDF_TOOLS_PATH` for an existing ESP-IDF installation. The setup script checks
229230
the SDK version before installing dependencies into the active environment.
230231
Use `--skip-idf` or `--skip-emulator` to install only the tools you need.
231232

@@ -304,15 +305,17 @@ fails the test. This also detects incomplete runs when the emulator's optional
304305
without rebuilding or starting the emulator.
305306

306307
The [CI wrapper](../../.ci/scripts/test_espressif.sh) composes these same steps,
307-
adds a host timeout, and collects logs and firmware. The
308+
adds a host timeout, and collects logs and firmware. It also runs the ESP-NN
309+
delegate's BundleIO fixtures with optimized S3 kernels and ANSI C reference
310+
kernels in separate jobs. The
308311
[GitHub Actions workflow](../../.github/workflows/test-espressif.yml) runs it on
309312
pull requests changing the ESP integration, pushes to `main` and `release/*`,
310313
weekly, and on manual dispatch. Branch and scheduled runs cover changes to
311314
shared runtime and export code.
312315

313-
This covers CPU execution and the ESP-IDF integration on S3. It does not establish
314-
performance or peripheral behavior on real boards, and the emulator does not
315-
support the original ESP32.
316+
This covers portable and ESP-NN delegate execution and ESP-IDF integration on S3.
317+
It does not establish performance or peripheral behavior on real boards, and the
318+
emulator does not support the original ESP32.
316319

317320
## Memory Considerations
318321

‎examples/espressif/setup.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ done
3434

3535
tools_dir="${ESPRESSIF_TOOLS_DIR:-${HOME}/.cache/executorch-espressif}"
3636
idf_version=v6.1
37-
emulator_version=0.48.0
37+
emulator_version=0.51.0
3838
emulator_installer_sha256=7d116867e9a54b8ab90b12fffec93eb5782b3b01f74191078be5278fa6fd5688
3939
mkdir -p "${tools_dir}"
4040
tools_dir=$(cd "${tools_dir}" && pwd)

0 commit comments

Comments
 (0)