Skip to content

Commit d0b0022

Browse files
authored
Merge branch 'main' into cortex-m-trunk-ci-m7
2 parents 9d18341 + 23b6ba0 commit d0b0022

863 files changed

Lines changed: 62910 additions & 12952 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ci/docker/build.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ case "${IMAGE_NAME}" in
8989
OS_VERSION=24.04
9090
GCC_VERSION=14
9191
;;
92+
executorch-ubuntu-26.04-gcc15)
93+
LINTRUNNER=""
94+
OS_VERSION=26.04
95+
GCC_VERSION=15
96+
;;
9297
*)
9398
echo "Invalid image name ${IMAGE_NAME}"
9499
exit 1

.ci/docker/common/install_docs_reqs.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ if [ -n "$BUILD_DOCS" ]; then
1515
curl --retry 3 --retry-all-errors -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
1616
sudo apt-get install -y nodejs
1717

18-
curl --retry 3 --retry-all-errors -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
19-
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
18+
curl --retry 3 --retry-all-errors -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/yarn-archive-keyring.gpg
19+
echo "deb [signed-by=/usr/share/keyrings/yarn-archive-keyring.gpg] https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
2020

2121
apt-get update
2222
apt-get install -y --no-install-recommends yarn

.ci/docker/common/install_linter.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,3 @@ source "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
1313
# NB: Install all linter dependencies, the caching of lintrunner init could be
1414
# done after Executorch becomes public
1515
pip_install -r requirements-lintrunner.txt
16-
17-
# Install google-java-format
18-
curl -L --retry 3 --retry-all-errors https://github.com/google/google-java-format/releases/download/v1.23.0/google-java-format_linux-x86-64 > /opt/google-java-format
19-
chmod +x /opt/google-java-format

.ci/scripts/bloaty-measure.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
# Usage: bash .ci/scripts/bloaty-measure.sh <job_name> <head_elf> <strip_tool>
9+
#
10+
# Runs bloaty against the head ELF, writes metadata.json + full.txt +
11+
# head_only.txt to artifacts-to-be-uploaded/, and appends a markdown table
12+
# to $GITHUB_STEP_SUMMARY.
13+
#
14+
# Best-effort: never exits non-zero — the size jobs that source this should
15+
# not fail because of a bloaty hiccup.
16+
17+
set -uo pipefail
18+
19+
job_name=$1
20+
head_elf=$2
21+
strip_tool=$3
22+
head_sha=${GITHUB_HEAD_SHA:-${GITHUB_SHA:-unknown}}
23+
24+
(
25+
# conda-forge bloaty depends on a newer libstdc++ than the ubuntu-22.04
26+
# docker images ship, so pull libstdcxx-ng into the same env and invoke
27+
# via `conda run` so library paths are set correctly.
28+
bloaty_env=/tmp/bloaty-conda-env
29+
if [[ ! -x "${bloaty_env}/bin/bloaty" ]]; then
30+
conda create -y -p "${bloaty_env}" -c conda-forge bloaty libstdcxx-ng || exit 1
31+
fi
32+
bloaty_cmd=("conda" "run" "--no-capture-output" "-p" "${bloaty_env}" "bloaty")
33+
"${bloaty_cmd[@]}" --version || exit 1
34+
35+
tmp_out=/tmp/bloaty-out
36+
rm -rf "${tmp_out}" && mkdir -p "${tmp_out}"
37+
BLOATY="${bloaty_cmd[*]}" python3 .github/scripts/bloaty_diff.py measure \
38+
--head "${head_elf}" \
39+
--job "${job_name}" \
40+
--binary-name size_test \
41+
--head-sha "${head_sha}" \
42+
--strip-tool "${strip_tool}" \
43+
--out "${tmp_out}" || exit 1
44+
mkdir -p artifacts-to-be-uploaded
45+
mv "${tmp_out}"/* artifacts-to-be-uploaded/
46+
) || echo "bloaty report failed; continuing"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
set -ex
9+
10+
# SwiftShader: software Vulkan adapter for GPU-less CI (LunarG SDK not needed).
11+
install_swiftshader() {
12+
_https_amazon_aws=https://ossci-android.s3.amazonaws.com
13+
_swiftshader_archive=swiftshader-abe07b943-prebuilt.tar.gz
14+
_swiftshader_dir=/tmp/swiftshader
15+
mkdir -p $_swiftshader_dir
16+
17+
_tmp_archive="/tmp/${_swiftshader_archive}"
18+
19+
curl --silent --show-error --location --fail --retry 3 --retry-all-errors \
20+
--output "${_tmp_archive}" "$_https_amazon_aws/${_swiftshader_archive}"
21+
22+
tar -C "${_swiftshader_dir}" -xzf "${_tmp_archive}"
23+
24+
export VK_ICD_FILENAMES="${_swiftshader_dir}/swiftshader/build/Linux/vk_swiftshader_icd.json"
25+
export LD_LIBRARY_PATH="${_swiftshader_dir}/swiftshader/build/Linux/:${LD_LIBRARY_PATH}"
26+
export ETVK_USING_SWIFTSHADER=1
27+
}
28+
29+
install_swiftshader
30+
bash backends/webgpu/scripts/setup-wgpu-native.sh

.ci/scripts/test_backend.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ if [[ "$FLOW" == *vulkan* ]]; then
5757
EXTRA_BUILD_ARGS+=" -DEXECUTORCH_BUILD_VULKAN=ON"
5858
fi
5959

60+
if [[ "$FLOW" == *webgpu* ]]; then
61+
# Setup swiftshader (software Vulkan adapter for GPU-less runners) and wgpu-native,
62+
# which are required to build and run the WebGPU delegate.
63+
source .ci/scripts/setup-webgpu-linux-deps.sh
64+
65+
EXTRA_BUILD_ARGS+=" -DEXECUTORCH_BUILD_WEBGPU=ON"
66+
fi
67+
6068
if [[ "$FLOW" == *arm* ]]; then
6169
if [[ "$SUITE" == "operators" ]]; then
6270
PYTEST_RETRY_ARGS=(--reruns 2 --reruns-delay 1)

.ci/scripts/test_minimal_wheel.sh

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#!/bin/bash
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
set -euxo pipefail
9+
10+
PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-python}"
11+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
12+
BUILD_VENV="${REPO_ROOT}/.venv-minimal-build"
13+
TEST_VENV="${REPO_ROOT}/.venv-minimal-test"
14+
15+
rm -rf "${BUILD_VENV}" "${TEST_VENV}" "${REPO_ROOT}/dist" "${REPO_ROOT}/pip-out"
16+
17+
"${PYTHON_EXECUTABLE}" -m venv "${BUILD_VENV}"
18+
source "${BUILD_VENV}/bin/activate"
19+
python -m pip install --upgrade pip
20+
python -m pip install \
21+
"cmake>=3.24,<4.0.0" \
22+
"numpy>=2.0.0" \
23+
packaging \
24+
pyyaml \
25+
setuptools \
26+
wheel \
27+
zstd \
28+
certifi \
29+
torch \
30+
torchvision \
31+
--index-url https://download.pytorch.org/whl/cpu \
32+
--extra-index-url https://pypi.org/simple
33+
34+
(
35+
cd "${REPO_ROOT}"
36+
EXECUTORCH_BUILD_MINIMAL=1 python setup.py bdist_wheel
37+
)
38+
39+
WHEEL_FILE="$(find "${REPO_ROOT}/dist" -maxdepth 1 -name 'executorch-*.whl' | head -1)"
40+
test -n "${WHEEL_FILE}"
41+
42+
python - "${WHEEL_FILE}" <<'PY'
43+
import re
44+
import sys
45+
import zipfile
46+
47+
wheel_file = sys.argv[1]
48+
with zipfile.ZipFile(wheel_file) as wheel:
49+
names = wheel.namelist()
50+
metadata_name = next(
51+
(name for name in names if name.endswith(".dist-info/METADATA")), None
52+
)
53+
if metadata_name is None:
54+
raise AssertionError(f"{wheel_file} has no METADATA")
55+
metadata_text = wheel.read(metadata_name).decode("utf-8")
56+
57+
for forbidden in (
58+
"executorch/backends/",
59+
"executorch/examples/",
60+
"executorch/kernels/",
61+
"executorch/runtime/",
62+
"executorch/devtools/",
63+
"executorch/extension/pybindings/",
64+
):
65+
matches = [name for name in names if name.startswith(forbidden)]
66+
if matches:
67+
raise AssertionError(f"{wheel_file} unexpectedly contains {matches[:5]}")
68+
69+
extensions = [
70+
name
71+
for name in names
72+
if name.endswith((".so", ".dylib", ".dll", ".pyd")) and "flatc" not in name
73+
]
74+
if extensions:
75+
raise AssertionError(f"{wheel_file} unexpectedly contains extensions: {extensions}")
76+
77+
78+
def _dist_name(requirement):
79+
name = re.split(r"[ ;\[<>=!~(]", requirement.strip(), maxsplit=1)[0]
80+
return re.sub(r"[-_.]+", "-", name).lower()
81+
82+
83+
# Only the core (non-extra) Requires-Dist entries define what a plain
84+
# "pip install" pulls; ignore the optional extras (cortex_m, vgf, ...).
85+
declared = {
86+
_dist_name(line.split(":", 1)[1])
87+
for line in metadata_text.splitlines()
88+
if line.startswith("Requires-Dist:") and "extra==" not in line.replace(" ", "")
89+
}
90+
# The minimal wheel must declare EXACTLY this core set and nothing else -- the
91+
# same names as `keep` in setup.py:_minimal_dependencies(). Exact match catches
92+
# both a heavy full-wheel dep leaking in (coremltools, pandas, or a re-added
93+
# mpmath/torch) and a required dep going missing.
94+
expected = {
95+
"flatbuffers",
96+
"numpy",
97+
"packaging",
98+
"pyyaml",
99+
"ruamel-yaml",
100+
"sympy",
101+
"tabulate",
102+
"typing-extensions",
103+
}
104+
if declared != expected:
105+
raise AssertionError(
106+
f"{wheel_file} minimal core deps mismatch: "
107+
f"unexpected={sorted(declared - expected)} missing={sorted(expected - declared)}"
108+
)
109+
PY
110+
111+
deactivate
112+
113+
"${PYTHON_EXECUTABLE}" -m venv "${TEST_VENV}"
114+
source "${TEST_VENV}/bin/activate"
115+
python -m pip install --upgrade pip
116+
# torch and torchvision are needed to export a model but are intentionally not
117+
# declared as wheel dependencies (consumers are expected to bring their own).
118+
python -m pip install \
119+
"torch" \
120+
"torchvision" \
121+
--index-url https://download.pytorch.org/whl/cpu \
122+
--extra-index-url https://pypi.org/simple
123+
# Install the minimal wheel WITHOUT --no-deps so pip resolves its declared
124+
# dependencies, confirming the slim set is correct and resolvable. (That no heavy
125+
# deps sneak in is guaranteed by the METADATA exact-match check above, which
126+
# covers the wheel's direct Requires-Dist.)
127+
python -m pip install \
128+
"${WHEEL_FILE}" \
129+
--index-url https://download.pytorch.org/whl/cpu \
130+
--extra-index-url https://pypi.org/simple
131+
132+
# flatc is the only compiled artifact in the minimal wheel and the reason it is
133+
# platform specific. Confirm it ships, resolves through _get_flatc_path() (the
134+
# executorch.data.bin lookup added for this build mode), and actually runs.
135+
python - <<'PY'
136+
import subprocess
137+
138+
from executorch.exir._serialize._flatbuffer import _get_flatc_path
139+
140+
flatc_path = _get_flatc_path()
141+
print(f"flatc resolved to: {flatc_path}")
142+
subprocess.run([flatc_path, "--version"], check=True)
143+
PY
144+
145+
python - <<'PY'
146+
from pathlib import Path
147+
148+
import torch
149+
from torch.export import export
150+
from torchvision.models import mobilenet_v2
151+
152+
from executorch.exir import to_edge_transform_and_lower
153+
154+
model = mobilenet_v2(weights=None).eval()
155+
example_inputs = (torch.randn(1, 3, 224, 224),)
156+
157+
edge_program = to_edge_transform_and_lower(export(model, example_inputs))
158+
executorch_program = edge_program.to_executorch()
159+
160+
output_path = Path("mv2_minimal.pte")
161+
with output_path.open("wb") as output_file:
162+
executorch_program.write_to_file(output_file)
163+
164+
assert output_path.stat().st_size > 0
165+
PY

.ci/scripts/unittest-macos-cmake.sh

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,19 @@ set -eux
1212
export TORCHINDUCTOR_CACHE_DIR="$(mktemp -d "${RUNNER_TEMP:-/tmp}/torchinductor_cache_XXXXXX")"
1313
trap 'rm -rf "${TORCHINDUCTOR_CACHE_DIR}"' EXIT
1414

15-
# Run pytest with coverage
16-
${CONDA_RUN} pytest -n auto --cov=./ --cov-report=xml
15+
# TODO(SS-JIA): AOTI tests hang on macOS CI runners — the thread blocks in
16+
# native C/C++ code (dlopen / inductor compilation) so faulthandler cannot
17+
# even produce a traceback. Diagnosis ongoing in #19886.
18+
AOTI_SKIPS=(
19+
--ignore=examples/models/llama3_2_vision/preprocess/test_preprocess.py
20+
--ignore=examples/models/llama3_2_vision/vision_encoder/test/test_vision_encoder.py
21+
--ignore=examples/models/llama3_2_vision/text_decoder/test/test_text_decoder.py
22+
--deselect=extension/llm/modules/test/test_position_embeddings.py::TilePositionalEmbeddingTest::test_tile_positional_embedding_aoti
23+
--deselect=extension/llm/modules/test/test_position_embeddings.py::TiledTokenPositionalEmbeddingTest::test_tiled_token_positional_embedding_aoti
24+
--deselect=extension/llm/modules/test/test_attention.py::AttentionTest::test_attention_aoti
25+
)
26+
27+
${CONDA_RUN} pytest -n auto --cov=./ --cov-report=xml "${AOTI_SKIPS[@]}"
1728
# Run gtest
1829
LLVM_PROFDATA="xcrun llvm-profdata" LLVM_COV="xcrun llvm-cov" \
1930
${CONDA_RUN} test/run_oss_cpp_tests.sh

.claude/skills/qualcomm/SKILL.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: qualcomm
3-
description: Build, test, or develop the QNN (Qualcomm AI Engine Direct) backend. Use when working on backends/qualcomm/, building QNN (use backends/qualcomm/scripts/build.sh), adding new ops or passes, running QNN delegate tests, or exporting models for Qualcomm HTP/GPU targets. Also exposes a Buck-vs-CMake parity workflow — invoke as `/qualcomm buck-fix`, `/qualcomm buck-cmake fix`, `/qualcomm buck-parity`, or any user request to fix `test-qnn-buck-build-linux` CI failures or check buck/cmake drift in backends/qualcomm/.
3+
description: Build, test, or develop the QNN (Qualcomm AI Engine Direct) backend. Use when working on backends/qualcomm/, building QNN (use backends/qualcomm/scripts/build.sh), adding new ops or passes, running QNN delegate tests, or exporting models for Qualcomm HTP/GPU targets. Also exposes a Buck-vs-CMake parity workflow — invoke as `/qualcomm buck-fix`, `/qualcomm buck-cmake fix`, `/qualcomm buck-parity`, or any user request to fix `test-qnn-buck-build-linux` CI failures or check buck/cmake drift in backends/qualcomm/. Also covers QNN intermediate-output / per-layer accuracy debugging — trigger on phrases like "QNN accuracy issue", "QNN output doesn't match CPU", "debug per-layer for QNN", "find which QNN layer is wrong".
44
---
55

66
# QNN (Qualcomm AI Engine Direct) Backend
@@ -25,6 +25,7 @@ When the user's request falls into one of these areas, read the corresponding fi
2525
| Model enablement | `model_enablement.md` | User asks to enable a new model end-to-end |
2626
| Buck vs CMake parity (pre-PR or fix red CI) | `buck_parity.md` | User changed BUCK / TARGETS / `targets.bzl` or `CMakeLists.txt` under `backends/qualcomm/`, added new `.cpp` / `.h` / `#include` there, is preparing to push a PR that touches QNN, **or** the `test-qnn-buck-build-linux` CI check on their PR is red and they want to fix it locally. Direct trigger: `/qualcomm buck-fix`. |
2727
| Profiling & debugging | `profiling.md` | User asks about profiling, optrace, QHAS, QAIRT Visualizer *(file TBD)* |
28+
| QNN intermediate-output / per-layer accuracy debugging | `qnn_intermediate_debugger.md` | User reports QNN-vs-CPU accuracy divergence, asks to debug per-layer / intermediate output for QNN, mentions `QNNIntermediateDebugger` / `QcomNumericalComparator`, or wants to find which layer causes a QNN accuracy drop. Workflow generates a new debug script from the user's existing example script. |
2829

2930
## Building
3031

.claude/skills/qualcomm/new_op_development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class DecomposeMyOp(ExportPass):
210210
return PassResult(graph_module, True)
211211
```
212212

213-
**Critical rules:** (1) handle both dialects via `EdgeOpOverload` check, (2) `copy_meta` on every new node, (3) lift scalars to tensors in edge dialect with `get_const_node`, (4) cache constants with `const_cache`, (5) for bool-output nodes use `callback=lambda m: {**m, "val": m["val"].to(torch.bool)}` in `create_node`.
213+
**Critical rules:** (1) handle both dialects via `EdgeOpOverload` check, (2) `copy_meta` on every new node, (3) lift scalars to tensors in edge dialect with `get_const_node`, (4) cache constants with `const_cache`, (5) for bool-output nodes use `callback=lambda m: {**m, "val": m["val"].to(torch.bool)}` in `create_node`, (6) **never pass kwargs** (like `dtype`/`device`) to `graph.create_node` for ATen ops — the ATen IR requires kwargs to be empty (`prepare_pt2e` asserts this); instead rely on `copy_meta` which propagates dtype/device via the FakeTensor in `node.meta["val"]`.
214214

215215
### Approach C: Built-in Decomposition Table
216216
**Ref:** `_passes/decompose_triu.py`. Uses `make_fx` + `get_decompositions`. Only works if PyTorch has a registered decomp.

0 commit comments

Comments
 (0)