diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml index 14e3e14e683..d2fa2f9a1a0 100644 --- a/.github/workflows/pull.yml +++ b/.github/workflows/pull.yml @@ -923,6 +923,44 @@ jobs: # Run QNN pass unit tests pytest -xvs backends/qualcomm/tests/test_passes.py + test-qnn-delegate-linux: + name: test-qnn-delegate-linux + uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main + permissions: + id-token: write + contents: read + strategy: + fail-fast: false + with: + runner: linux.2xlarge + docker-image: ci-image:executorch-ubuntu-22.04-qnn-sdk + submodules: 'recursive' + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + timeout: 90 + script: | + # The generic Linux job chooses to use base env, not the one setup by the image + CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]") + conda activate "${CONDA_ENV}" + + PYTHON_EXECUTABLE=python bash .ci/scripts/setup-qnn-deps.sh + # Source (not bash) so QNN_SDK_ROOT stays in the environment + PYTHON_EXECUTABLE=python source .ci/scripts/build-qnn-sdk.sh + + # Editable install so the PyQnnManagerAdaptor .so built by build-qnn-sdk.sh + # is visible in the source tree + CMAKE_ARGS="-DEXECUTORCH_BUILD_QNN=ON -DQNN_SDK_ROOT=$QNN_SDK_ROOT -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON" \ + PYTHON_EXECUTABLE=python bash .ci/scripts/setup-linux.sh --build-tool cmake --editable true + + pip install -r requirements-examples.txt + + # Enable conftest.py to call setup_environment() for pytest runs + export QNN_DELEGATE_TEST=1 + export LD_LIBRARY_PATH="$QNN_SDK_ROOT/lib/x86_64-linux-clang/:$(realpath build-x86/lib/):${LD_LIBRARY_PATH:-}" + + # Run operator test classes only. + pytest -vs backends/qualcomm/tests/test_qnn_delegate.py \ + -k "TestQNNFloatingPointOperator or TestQNNQuantizedOperator" + test-phi-3-mini-runner-linux: name: test-phi-3-mini-runner-linux uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main diff --git a/backends/qualcomm/tests/conftest.py b/backends/qualcomm/tests/conftest.py new file mode 100644 index 00000000000..0230c3d5cd2 --- /dev/null +++ b/backends/qualcomm/tests/conftest.py @@ -0,0 +1,61 @@ +# Copyright (c) Qualcomm Innovation Center, Inc. +# All rights reserved +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""Pytest conftest for test_qnn_delegate.py. + +When test_qnn_delegate.py is invoked via pytest (instead of as __main__), +setup_environment() is never called, so TestQNN class attributes remain at +their defaults (None / empty string / False). This conftest bridges the gap +by calling setup_environment() with a synthetic argv built from environment +variables, keeping a single source of truth for attribute assignment. + +Required env vars for x86 simulator execution: + QNN_SOC_MODEL - e.g. "SM8650" + QNN_SDK_ROOT - path to QNN SDK (also used by verify_output) + +Optional env vars (with defaults shown): + QNN_BACKEND - "htp" + QNN_BUILD_FOLDER - "build-x86" + QNN_ENABLE_X86_64 - "1" to enable x86 simulator mode + EXECUTORCH_ROOT - cwd + QNN_ARTIFACT_DIR - "/tmp/qnn_test_artifacts" +""" + +import os +import sys + + +def pytest_configure(config): + if os.environ.get("QNN_DELEGATE_TEST") != "1": + return + + argv = [ + "test_qnn_delegate.py", + "--soc_model", + os.environ.get("QNN_SOC_MODEL", "SM8650"), + "--backend", + os.environ.get("QNN_BACKEND", "htp"), + "--build_folder", + os.environ.get("QNN_BUILD_FOLDER", "build-x86"), + "--executorch_root", + os.environ.get("EXECUTORCH_ROOT", os.getcwd()), + "--artifact_dir", + os.environ.get("QNN_ARTIFACT_DIR", "/tmp/qnn_test_artifacts"), + ] + + if os.environ.get("QNN_ENABLE_X86_64", "1") == "1": + argv.append("--enable_x86_64") + + original_argv = sys.argv + try: + sys.argv = argv + from executorch.backends.qualcomm.tests.test_qnn_delegate import ( + setup_environment, + ) + + setup_environment() + finally: + sys.argv = original_argv diff --git a/backends/qualcomm/tests/test_qnn_delegate.py b/backends/qualcomm/tests/test_qnn_delegate.py index 3e236952933..21092d93000 100644 --- a/backends/qualcomm/tests/test_qnn_delegate.py +++ b/backends/qualcomm/tests/test_qnn_delegate.py @@ -1315,6 +1315,8 @@ def test_qnn_backend_is_inf(self): self.lower_module_and_test_output(module, sample_input) def test_qnn_backend_is_nan(self): + if self.enable_x86_64: + self.skipTest("isnan produces incorrect results on x86 simulator") module = IsNan() # noqa: F405 sample_inputs = [ ( @@ -2189,7 +2191,9 @@ def test_qnn_backend_causal_mask(self): module = CausalMask() # noqa: F405 torch.manual_seed(8) sample_input = (torch.rand((1, 1, 1, 128)) < 0.5,) - self.lower_module_and_test_output(module, sample_input) + self.lower_module_and_test_output( + module, sample_input, skip_mutable_buffer=self.enable_x86_64 + ) def test_qnn_backend_chunk_add(self): module = ChunkAdd() # noqa: F405 @@ -4781,7 +4785,9 @@ def test_qnn_backend_causal_mask(self): module = CausalMask() # noqa: F405 sample_input = (torch.rand((1, 1, 1, 128)) < 0.5,) module = self.get_qdq_module(module, sample_input) - self.lower_module_and_test_output(module, sample_input) + self.lower_module_and_test_output( + module, sample_input, skip_mutable_buffer=self.enable_x86_64 + ) def test_qnn_backend_chunk_add(self): module = ChunkAdd() # noqa: F405