Skip to content

Commit 4a4f5a0

Browse files
authored
custom fbcode serialize stage to run FVP internally on arm ops tests (#14070)
Summary: update the codebase to allow a system whereby: - the test inventory in https://www.internalfb.com/code/fbsource/fbcode/executorch/backends/arm/test/ops/, which until now runs on open source CI can all be exercised internally on our internal diff-time sandcastle and CI runs - those tests can **transparently** switch between running an internal version of FVP using Meta's FVP runtimes, build configs and artifacts when run in fbsrouce, but then use the open-source FVp runtime when executed in github opens-ource CI Differential Revision: D81159036
1 parent ea4f004 commit 4a4f5a0

File tree

5 files changed

+107
-48
lines changed

5 files changed

+107
-48
lines changed

backends/arm/test/TARGETS

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,17 @@ runtime.python_library(
4040
)
4141

4242
runtime.python_library(
43-
name = "arm_tester",
44-
srcs = glob(["tester/*.py"]),
43+
name = "arm_tester_serialize",
44+
srcs = ["tester/serialize.py"],
45+
deps = [
46+
"//executorch/backends/xnnpack/test/tester:tester",
47+
"//executorch/devtools/backend_debug:delegation_info",
48+
]
49+
)
50+
51+
runtime.python_library(
52+
name = "arm_tester_lib",
53+
srcs = glob(["tester/*.py"], exclude = ["tester/serialize.py"]),
4554
deps = [
4655
":common",
4756
"//executorch/backends/xnnpack/test/tester:tester",
@@ -55,4 +64,13 @@ runtime.python_library(
5564
]
5665
)
5766

67+
68+
runtime.python_library(
69+
name = "arm_tester",
70+
deps = [
71+
"//executorch/backends/arm/test:arm_tester_lib",
72+
"//executorch/backends/arm/test:arm_tester_serialize",
73+
]
74+
)
75+
5876
define_arm_tests()

backends/arm/test/ops/test_tanh.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,27 @@ def test_tanh_tosa_INT(test_data: Tuple):
7070

7171

7272
@common.parametrize("test_data", test_data_suite)
73+
@common.XfailIfNoCorstone300
7374
def test_tanh_u55_INT(test_data: Tuple):
7475
pipeline = EthosU55PipelineINT[input_t1](
7576
Tanh(),
7677
(test_data(),),
7778
aten_op,
7879
exir_ops=[],
79-
run_on_fvp=False,
80+
run_on_fvp=True,
8081
)
8182
pipeline.run()
8283

8384

8485
@common.parametrize("test_data", test_data_suite)
86+
@common.XfailIfNoCorstone320
8587
def test_tanh_u85_INT(test_data: Tuple):
8688
pipeline = EthosU85PipelineINT[input_t1](
8789
Tanh(),
8890
(test_data(),),
8991
aten_op,
9092
exir_ops=[],
91-
run_on_fvp=False,
93+
run_on_fvp=True,
9294
)
9395
pipeline.run()
9496

backends/arm/test/targets.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# load("//caffe2/test/fb:defs.bzl", "define_tests")
2+
load("@fbsource//tools/build_defs:fbsource_utils.bzl", "is_fbcode")
23
load("@fbcode_macros//build_defs:python_pytest.bzl", "python_pytest")
34
load("@bazel_skylib//lib:paths.bzl", "paths")
45

@@ -59,7 +60,7 @@ def define_arm_tests():
5960
"//executorch/kernels/quantized:custom_ops_generated_lib",
6061
],
6162
deps = [
62-
"//executorch/backends/arm/test:arm_tester",
63+
"//executorch/backends/arm/test/tester/fb:arm_tester_fb" if is_fbcode else "//executorch/backends/arm/test:arm_tester",
6364
"//executorch/backends/arm/test:conftest",
6465
"//executorch/backends/arm:ethosu",
6566
"//executorch/backends/arm/tosa:compile_spec",

backends/arm/test/tester/arm_tester.py

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import logging
99

10-
import os
1110
from collections import Counter
1211
from pprint import pformat
1312
from typing import (
@@ -42,17 +41,15 @@
4241
)
4342
from executorch.backends.arm.test.runner_utils import (
4443
dbg_tosa_fb_to_json,
45-
get_elf_path,
4644
get_output_quantization_params,
47-
get_target_board,
48-
run_target,
4945
TosaReferenceModelDispatch,
5046
)
5147

5248
from executorch.backends.arm.test.tester.analyze_output_utils import (
5349
dump_error_output,
5450
print_error_diffs,
5551
)
52+
from executorch.backends.arm.test.tester.serialize import Serialize
5653
from executorch.backends.arm.tosa import TosaSpecification
5754
from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec
5855
from executorch.backends.arm.tosa.mapping import extract_tensor_meta
@@ -90,7 +87,6 @@
9087

9188
from torch.export.graph_signature import ExportGraphSignature, InputSpec, OutputSpec
9289
from torch.fx import Graph
93-
from torch.utils._pytree import tree_flatten
9490

9591

9692
logger = logging.getLogger(__name__)
@@ -179,43 +175,6 @@ def run(
179175
)
180176

181177

182-
class Serialize(tester.Serialize):
183-
def __init__(self, compile_spec: ArmCompileSpec, timeout):
184-
super().__init__()
185-
self.timeout = timeout
186-
self.executorch_program_manager: ExecutorchProgramManager | None
187-
self.compile_spec = compile_spec
188-
189-
def run(self, artifact: ExecutorchProgramManager, inputs=None) -> None:
190-
super().run(artifact, inputs)
191-
# Keep the entire ExecutorchProgramManager for execution.
192-
self.executorch_program_manager = artifact
193-
194-
def run_artifact(self, inputs):
195-
if self.executorch_program_manager is None:
196-
raise RuntimeError(
197-
"Tried running artifact from Serialize stage without running the stage."
198-
)
199-
inputs_flattened, _ = tree_flatten(inputs)
200-
intermediate_path = self.compile_spec.get_intermediate_path()
201-
target_board = get_target_board(self.compile_spec)
202-
elf_path = get_elf_path(target_board)
203-
204-
if not os.path.exists(elf_path):
205-
raise FileNotFoundError(
206-
f"Did not find build arm_executor_runner in path {elf_path}, run setup_testing.sh?"
207-
)
208-
209-
return run_target(
210-
self.executorch_program_manager,
211-
inputs_flattened,
212-
intermediate_path,
213-
target_board,
214-
elf_path,
215-
self.timeout,
216-
)
217-
218-
219178
class ToExecutorch(tester.ToExecutorch):
220179
def run_artifact(self, inputs):
221180
with TosaReferenceModelDispatch():
@@ -419,7 +378,11 @@ def serialize(
419378
self, serialize_stage: Optional[Serialize] = None, timeout: int = 480
420379
):
421380
if serialize_stage is None:
422-
serialize_stage = Serialize(self.compile_spec, timeout)
381+
serialize_stage = Serialize(
382+
compile_spec=self.compile_spec,
383+
module=self.original_module,
384+
timeout=timeout,
385+
)
423386
assert (
424387
self.compile_spec.get_intermediate_path() is not None
425388
), "Can't dump serialized file when compile specs do not contain an artifact path."
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright 2024-2025 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
import logging
7+
import os
8+
from typing import Optional
9+
10+
import executorch.backends.xnnpack.test.tester.tester as tester
11+
12+
import torch.fx
13+
14+
from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec
15+
16+
from executorch.backends.arm.test.runner_utils import (
17+
get_elf_path,
18+
get_target_board,
19+
run_target,
20+
)
21+
22+
from executorch.exir import ExecutorchProgramManager
23+
from torch.utils._pytree import tree_flatten
24+
25+
26+
logger = logging.getLogger(__name__)
27+
28+
29+
class Serialize(tester.Serialize):
30+
def __init__(
31+
self,
32+
compile_spec: ArmCompileSpec,
33+
module: Optional[torch.nn.Module],
34+
timeout: int = 120,
35+
):
36+
"""
37+
Args:
38+
compile_spec: CompileSpecs to be used for serialization.
39+
module: Original Module to be used for serialization. Optional - can be used for reference output generation.
40+
timeout: Timeout for fvp. Default is 120 seconds.
41+
"""
42+
super().__init__()
43+
self.module = module
44+
self.timeout = timeout
45+
self.executorch_program_manager: ExecutorchProgramManager | None
46+
self.compile_spec = compile_spec
47+
48+
def run(self, artifact: ExecutorchProgramManager, inputs=None) -> None:
49+
super().run(artifact, inputs)
50+
# Keep the entire ExecutorchProgramManager for execution.
51+
self.executorch_program_manager = artifact
52+
53+
def run_artifact(self, inputs):
54+
if self.executorch_program_manager is None:
55+
raise RuntimeError(
56+
"Tried running artifact from Serialize stage without running the stage."
57+
)
58+
inputs_flattened, _ = tree_flatten(inputs)
59+
intermediate_path = self.compile_spec.get_intermediate_path()
60+
target_board = get_target_board(self.compile_spec)
61+
elf_path = get_elf_path(target_board)
62+
63+
if not os.path.exists(elf_path):
64+
raise FileNotFoundError(
65+
f"Did not find build arm_executor_runner in path {elf_path}, run setup_testing.sh?"
66+
)
67+
68+
return run_target(
69+
self.executorch_program_manager,
70+
inputs_flattened,
71+
intermediate_path,
72+
target_board,
73+
elf_path,
74+
self.timeout,
75+
)

0 commit comments

Comments
 (0)