Skip to content

Commit 3baf2c0

Browse files
committed
[Backend Tester] Add ARM TOSA flow
ghstack-source-id: 7540d11 ghstack-comment-id: 3277010040 Pull-Request: #14190
1 parent 242096f commit 3baf2c0

File tree

7 files changed

+93
-6
lines changed

7 files changed

+93
-6
lines changed

.ci/scripts/test_backend_linux.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,17 @@ if [[ "$FLOW" == *qnn* ]]; then
4141
fi
4242

4343
if [[ "$FLOW" == *vulkan* ]]; then
44-
# Setup swiftshader and Vulkan SDK which are required to build the Vulkan delegate
44+
# Setup swiftshader and Vulkan SDK which are required to build the Vulkan delegate.
4545
source .ci/scripts/setup-vulkan-linux-deps.sh
4646

4747
EXTRA_BUILD_ARGS+=" -DEXECUTORCH_BUILD_VULKAN=ON"
4848
fi
4949

50+
if [[ "$FLOW" == *arm* ]]; then
51+
# Setup ARM deps.
52+
.ci/scripts/setup-arm-baremetal-tools.sh
53+
fi
54+
5055
# We need the runner to test the built library.
5156
PYTHON_EXECUTABLE=python CMAKE_ARGS="$EXTRA_BUILD_ARGS" .ci/scripts/setup-linux.sh --build-tool cmake --build-mode Release --editable true
5257

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Test ARM Backend
2+
3+
on:
4+
schedule:
5+
- cron: 0 2 * * *
6+
push:
7+
tags:
8+
- ciflow/nightly/*
9+
pull_request:
10+
paths:
11+
- .github/workflows/test-backend-arm.yml
12+
- .github/workflows/_test_backend.yml
13+
workflow_dispatch:
14+
15+
concurrency:
16+
group: ${{ github.workflow }}--${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
test-xnnpack:
21+
uses: ./.github/workflows/_test_backend.yml
22+
with:
23+
backend: xnnpack
24+
flows: '["arm-tosa"]'
25+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
26+
timeout: 120
27+
run-linux: true

backends/arm/test/tester/arm_tester.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565

6666
from executorch.backends.arm.vgf_partitioner import VgfPartitioner
6767

68+
from executorch.backends.test.harness.error_statistics import ErrorStatistics
6869
from executorch.backends.test.harness.stages import Stage, StageType
6970
from executorch.backends.xnnpack.test.tester import Tester
7071
from executorch.devtools.backend_debug import get_delegation_info
@@ -379,6 +380,7 @@ def to_edge_transform_and_lower(
379380
transform_passes: Optional[
380381
Union[Sequence[PassType], Dict[str, Sequence[PassType]]]
381382
] = None,
383+
generate_etrecord: bool = False,
382384
):
383385
if to_edge_and_lower_stage is None:
384386
if partitioners is None:
@@ -412,7 +414,9 @@ def to_edge_transform_and_lower(
412414
to_edge_and_lower_stage.partitioners = partitioners
413415
if edge_compile_config is not None:
414416
to_edge_and_lower_stage.edge_compile_conf = edge_compile_config
415-
return super().to_edge_transform_and_lower(to_edge_and_lower_stage)
417+
return super().to_edge_transform_and_lower(
418+
to_edge_and_lower_stage, generate_etrecord=generate_etrecord
419+
)
416420

417421
def to_executorch(self, to_executorch_stage: Optional[ToExecutorch] | None = None):
418422
if to_executorch_stage is None:
@@ -443,6 +447,7 @@ def run_method_and_compare_outputs(
443447
qtol=0,
444448
error_callbacks=None,
445449
run_eager_mode=False,
450+
statistics_callback: Callable[[ErrorStatistics], None] | None = None,
446451
):
447452
"""
448453
Compares the run_artifact output of 'stage' with the output of a reference stage.
@@ -698,10 +703,17 @@ def _compare_outputs(
698703
rtol=1e-03,
699704
qtol=0,
700705
error_callbacks=None,
706+
statistics_callback: Callable[[ErrorStatistics], None] | None = None,
701707
):
702708
try:
703709
super()._compare_outputs(
704-
reference_output, stage_output, quantization_scale, atol, rtol, qtol
710+
reference_output,
711+
stage_output,
712+
quantization_scale,
713+
atol,
714+
rtol,
715+
qtol,
716+
statistics_callback=statistics_callback,
705717
)
706718
except AssertionError as e:
707719
if error_callbacks is None:

backends/test/suite/flow.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class TestFlow:
3838
skip_patterns: list[str] = field(default_factory=lambda: [])
3939
""" Tests with names containing any substrings in this list are skipped. """
4040

41+
supports_serialize: bool = True
42+
""" True if the test flow supports the Serialize stage. """
43+
4144
def should_skip_test(self, test_name: str) -> bool:
4245
return any(pattern in test_name for pattern in self.skip_patterns)
4346

@@ -115,4 +118,13 @@ def all_flows() -> dict[str, TestFlow]:
115118
except Exception as e:
116119
logger.info(f"Skipping QNN flow registration: {e}")
117120

121+
try:
122+
from executorch.backends.test.suite.flows.arm import ARM_TOSA_FLOW
123+
124+
flows += [
125+
ARM_TOSA_FLOW,
126+
]
127+
except Exception as e:
128+
logger.info(f"Skipping ARM flow registration: {e}")
129+
118130
return {f.name: f for f in flows if f is not None}

backends/test/suite/flows/arm.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from executorch.backends.arm.test import common
2+
from executorch.backends.arm.test.tester.arm_tester import ArmTester
3+
from executorch.backends.test.suite.flow import TestFlow
4+
5+
def _create_arm_tester_tosa_fp(*args, **kwargs) -> ArmTester:
6+
kwargs["compile_spec"] = common.get_tosa_compile_spec(tosa_spec="TOSA-1.0+FP")
7+
8+
return ArmTester(
9+
*args,
10+
**kwargs,
11+
)
12+
13+
def _create_tosa_flow() -> TestFlow:
14+
return TestFlow(
15+
"arm_tosa",
16+
backend="arm",
17+
tester_factory=_create_arm_tester_tosa_fp,
18+
supports_serialize=False,
19+
)
20+
21+
ARM_TOSA_FLOW = _create_tosa_flow()

backends/test/suite/runner.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,11 @@ def build_result(
191191
# Only run the runtime portion if something was delegated (or the flow doesn't delegate)
192192
if is_delegated or not flow.is_delegated:
193193
try:
194-
tester.to_executorch().serialize()
195-
extra_stats["pte_size_bytes"] = len(tester.get_artifact())
194+
tester.to_executorch()
195+
196+
if flow.supports_serialize:
197+
tester.serialize()
198+
extra_stats["pte_size_bytes"] = len(tester.get_artifact())
196199
except Exception as e:
197200
# We could introduce a result value for this, but I'm not sure it's necessary.
198201
# We can do this if we ever see to_executorch() or serialize() fail due a backend issue.

export/tests/test_target_recipes.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@
77
# pyre-strict
88

99
import logging
10+
import sys
1011
import unittest
1112

1213
import torch
13-
from executorch.backends.apple.coreml.recipes import CoreMLRecipeProvider # pyre-ignore
1414
from executorch.backends.xnnpack.recipes.xnnpack_recipe_provider import (
1515
XNNPACKRecipeProvider,
1616
)
1717
from executorch.export import export, recipe_registry
1818
from executorch.export.target_recipes import get_ios_recipe
1919
from executorch.runtime import Runtime
2020

21+
if sys.platform != "win32":
22+
from executorch.backends.apple.coreml.recipes import ( # pyre-ignore
23+
CoreMLRecipeProvider,
24+
)
25+
2126

2227
class TestTargetRecipes(unittest.TestCase):
2328
"""Test target recipes."""
@@ -32,6 +37,7 @@ def setUp(self) -> None:
3237
def tearDown(self) -> None:
3338
super().tearDown()
3439

40+
@unittest.skipif(sys.platform == "win32", "Core ML is not available on Windows.")
3541
def test_ios_fp32_recipe_with_xnnpack_fallback(self) -> None:
3642
# Linear ops skipped by coreml but handled by xnnpack
3743
class Model(torch.nn.Module):
@@ -107,6 +113,7 @@ def forward(self, x, y):
107113
et_output = session.run_method("forward", example_inputs[0])
108114
logging.info(f"et output {et_output}")
109115

116+
@unittest.skipif(sys.platform == "win32", "Core ML is not available on Windows.")
110117
def test_ios_quant_recipes(self) -> None:
111118
class Model(torch.nn.Module):
112119
def __init__(self):

0 commit comments

Comments
 (0)