Skip to content

Commit b7b6117

Browse files
authored
Arm backend: ArmTester support testing with portable ops (pytorch#15278)
### Summary This will enable model testing where some ops are not fully delegated, like done in the backend flow test suite. This also remove the unused fast_fvp pytest flag and always run the Corstone-300/320 in fast mode as we are never interesting in PMU cycle numbers in the pytesting anyway, this gives more then a 2x speedboost on some models. This will also extend the FVP timeout to 20 min for backend flows and increase allocation pool to 80MB to make it possible to tests larger models. For normal unit tests the timeout is set to 10 min ### Test plan Arm backend suite test will tests this. Signed-off-by: Zingo Andersen <[email protected]>
1 parent dcc9a91 commit b7b6117

File tree

8 files changed

+52
-31
lines changed

8 files changed

+52
-31
lines changed

backends/arm/test/common.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def get_u55_compile_spec(
8787
macs: int = 128,
8888
system_config: str = "Ethos_U55_High_End_Embedded",
8989
memory_mode: str = "Shared_Sram",
90-
extra_flags: str = "--debug-force-regor --output-format=raw",
90+
extra_flags: str = "--debug-force-regor --output-format=raw --arena-cache-size=2097152",
9191
custom_path: Optional[str] = None,
9292
config: Optional[str] = None,
9393
tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None,
@@ -122,7 +122,7 @@ def get_u85_compile_spec(
122122
macs: int = 128,
123123
system_config="Ethos_U85_SYS_DRAM_Mid",
124124
memory_mode="Shared_Sram",
125-
extra_flags="--output-format=raw",
125+
extra_flags="--output-format=raw --arena-cache-size=2097152",
126126
custom_path: Optional[str] = None,
127127
config: Optional[str] = None,
128128
tosa_debug_mode: EthosUCompileSpec.DebugMode | None = None,

backends/arm/test/conftest.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ def pytest_configure(config):
2525
if getattr(config.option, "llama_inputs", False) and config.option.llama_inputs:
2626
pytest._test_options["llama_inputs"] = config.option.llama_inputs # type: ignore[attr-defined]
2727

28-
pytest._test_options["fast_fvp"] = False # type: ignore[attr-defined]
29-
if getattr(config.option, "fast_fvp", False):
30-
pytest._test_options["fast_fvp"] = config.option.fast_fvp # type: ignore[attr-defined]
31-
3228
pytest._test_options["tosa_version"] = "1.0" # type: ignore[attr-defined]
3329
if config.option.arm_run_tosa_version:
3430
pytest._test_options["tosa_version"] = config.option.arm_run_tosa_version
@@ -49,7 +45,6 @@ def try_addoption(*args, **kwargs):
4945

5046
try_addoption("--arm_quantize_io", action="store_true", help="Deprecated.")
5147
try_addoption("--arm_run_corstoneFVP", action="store_true", help="Deprecated.")
52-
try_addoption("--fast_fvp", action="store_true")
5348
try_addoption(
5449
"--llama_inputs",
5550
nargs="+",

backends/arm/test/ops/test_permute.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,7 @@ def test_permute_tosa_INT(test_data: torch.Tensor):
7676
pipeline.run()
7777

7878

79-
@common.parametrize(
80-
"test_data",
81-
test_data_suite,
82-
xfails={"rank_4_3": "MLETORCH-955 : Permutation numerical diff for u55"},
83-
)
79+
@common.parametrize("test_data", test_data_suite)
8480
@common.XfailIfNoCorstone300
8581
def test_permute_u55_INT(test_data):
8682
test_data, dims = test_data()

backends/arm/test/runner_utils.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
)
2929

3030
from executorch.backends.arm.ethosu import EthosUCompileSpec
31-
from executorch.backends.arm.test.conftest import is_option_enabled
3231
from executorch.backends.arm.tosa.compile_spec import TosaCompileSpec
3332
from executorch.backends.arm.tosa.specification import Tosa_1_00, TosaSpecification
3433
from executorch.backends.arm.vgf import VgfCompileSpec
@@ -414,10 +413,6 @@ def run_corstone(
414413
"The argument passed to the FVP should be less than 256 characters long, otherwise it gets truncated"
415414
)
416415

417-
ethos_u_extra_args = ""
418-
if is_option_enabled("fast_fvp"):
419-
ethos_u_extra_args = ethos_u_extra_args + "--fast"
420-
421416
match target_board:
422417
case "corstone-300":
423418
command_args = [
@@ -435,12 +430,12 @@ def run_corstone(
435430
"-C",
436431
"cpu0.semihosting-stack_base=0",
437432
"-C",
438-
f"ethosu.extra_args='{ethos_u_extra_args}'",
439-
"-C",
440433
"cpu0.semihosting-heap_limit=0",
441434
"-C",
442435
f"cpu0.semihosting-cwd={intermediate_path}",
443436
"-C",
437+
"ethosu.extra_args='--fast'",
438+
"-C",
444439
f"cpu0.semihosting-cmd_line='{cmd_line}'",
445440
"-a",
446441
str(elf_path),
@@ -473,7 +468,7 @@ def run_corstone(
473468
"-C",
474469
f"mps4_board.subsystem.cpu0.semihosting-cwd={intermediate_path}",
475470
"-C",
476-
f"mps4_board.subsystem.ethosu.extra_args='{ethos_u_extra_args}'",
471+
"mps4_board.subsystem.ethosu.extra_args='--fast'",
477472
"-C",
478473
f"mps4_board.subsystem.cpu0.semihosting-cmd_line='{cmd_line}'",
479474
"-a",
@@ -719,30 +714,35 @@ def assert_elf_path_exists(elf_path):
719714
)
720715

721716

722-
def get_elf_path(target_board):
717+
def get_elf_path(target_board: str, use_portable_ops: bool = False):
723718
if target_board not in VALID_TARGET:
724719
raise ValueError(f"Unsupported target: {target_board}")
725720

721+
if use_portable_ops:
722+
portable_ops_str = "portable-ops_"
723+
else:
724+
portable_ops_str = ""
725+
726726
if target_board in ("corstone-300", "corstone-320"):
727727
elf_path = os.path.join(
728728
"arm_test",
729-
f"arm_semihosting_executor_runner_{target_board}",
729+
f"arm_semihosting_executor_runner_{portable_ops_str}{target_board}",
730730
"arm_executor_runner",
731731
)
732732
assert_elf_path_exists(elf_path)
733733
elif target_board == "vkml_emulation_layer":
734734
elf_path = os.path.join(
735-
"arm_test/arm_executor_runner_vkml",
735+
f"arm_test/arm_executor_runner_{portable_ops_str}vkml",
736736
"executor_runner",
737737
)
738738
assert_elf_path_exists(elf_path)
739739

740740
return elf_path
741741

742742

743-
def arm_executor_runner_exists(target_board):
743+
def arm_executor_runner_exists(target_board: str, use_portable_ops: bool = False):
744744
try:
745-
get_elf_path(target_board)
745+
get_elf_path(target_board, use_portable_ops=use_portable_ops)
746746
except:
747747
return False
748748
else:

backends/arm/test/setup_testing.sh

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ script_dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
1010
et_root_dir=$(realpath "${script_dir}/../../..")
1111
build_executor_runner=${et_root_dir}/backends/arm/scripts/build_executor_runner.sh
1212
build_root_test_dir=${et_root_dir}/arm_test/arm_semihosting_executor_runner
13+
extraflags="-DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=83886080"
1314

14-
${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --output="${build_root_test_dir}_corstone-300"
15-
${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --output="${build_root_test_dir}_corstone-320"
15+
# By default tests with an elf without any portable_ops
16+
# If you supply use_portable_ops=True when creating the ArmTester()
17+
# you will instead test with some portable ops compiled in, see list below.
18+
19+
#--target --system_config --memory_mode should match the ArmTester used setup see backends/arm/test/common.py
20+
21+
${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --output="${build_root_test_dir}_corstone-300" --extra_build_flags=${extraflags}
22+
${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --output="${build_root_test_dir}_corstone-320" --extra_build_flags=${extraflags}
23+
24+
# List of portable ops used by testing, this is mainly used to test models in the flow
25+
# test setup to make sure models that are not fully delegated can still be tested and run OK
26+
# To use this you can set use_portable_ops=True when creating ArmTester()
27+
28+
portable_ops_list_u55="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::squeeze_copy.dims,dim_order_ops::_clone_dim_order.out"
29+
portable_ops_list_u85="aten::permute_copy.out,aten::convolution.out,aten::relu.out,aten::_native_batch_norm_legit_no_training.out,aten::as_strided_copy.out,aten::mean.out,aten::full_like.out,aten::bmm.out,aten::scalar_tensor.out,aten::index.Tensor_out,aten::where.self_out"
30+
31+
${build_executor_runner} --pte=semihosting --target=ethos-u55-128 --system_config=Ethos_U55_High_End_Embedded --memory_mode=Shared_Sram --select_ops_list="${portable_ops_list_u55}" --output="${build_root_test_dir}_portable-ops_corstone-300" --extra_build_flags=${extraflags}
32+
${build_executor_runner} --pte=semihosting --target=ethos-u85-128 --system_config=Ethos_U85_SYS_DRAM_Mid --memory_mode=Dedicated_Sram_384KB --select_ops_list="${portable_ops_list_u85}" --output="${build_root_test_dir}_portable-ops_corstone-320" --extra_build_flags=${extraflags}

backends/arm/test/tester/arm_tester.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ def __init__(
250250
transform_passes: Optional[
251251
Union[Sequence[PassType], Dict[str, Sequence[PassType]]]
252252
] = None,
253+
use_portable_ops: bool = False,
254+
timeout: int = 600,
253255
):
254256
"""
255257
Args:
@@ -271,6 +273,8 @@ def __init__(
271273
# Initial model needs to be set as a *possible* but not yet added Stage, therefore add None entry.
272274
self.stages[StageType.INITIAL_MODEL] = None
273275
self._run_stage(InitialModel(self.original_module))
276+
self.use_portable_ops = use_portable_ops
277+
self.timeout = timeout
274278

275279
def quantize(
276280
self,
@@ -348,13 +352,15 @@ def to_executorch(self, to_executorch_stage: Optional[ToExecutorch] | None = Non
348352
return super().to_executorch(to_executorch_stage)
349353

350354
def serialize(
351-
self, serialize_stage: Optional[Serialize] = None, timeout: int = 480
355+
self,
356+
serialize_stage: Optional[Serialize] = None,
352357
):
353358
if serialize_stage is None:
354359
serialize_stage = Serialize(
355360
compile_spec=self.compile_spec,
356361
module=self.original_module,
357-
timeout=timeout,
362+
use_portable_ops=self.use_portable_ops,
363+
timeout=self.timeout,
358364
)
359365
assert (
360366
self.compile_spec.get_intermediate_path() is not None

backends/arm/test/tester/serialize.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,22 @@ def __init__(
3131
self,
3232
compile_spec: ArmCompileSpec,
3333
module: Optional[torch.nn.Module],
34+
use_portable_ops: bool = False,
3435
timeout: int = 120,
3536
):
3637
"""
3738
Args:
3839
compile_spec: CompileSpecs to be used for serialization.
3940
module: Original Module to be used for serialization. Optional - can be used for reference output generation.
41+
portable_ops: If True tests with compiled in portable ops, default is to test without this to get error if not fully delegated
4042
timeout: Timeout for fvp. Default is 120 seconds.
4143
"""
4244
super().__init__()
4345
self.module = module
4446
self.timeout = timeout
4547
self.executorch_program_manager: ExecutorchProgramManager | None
4648
self.compile_spec = compile_spec
49+
self.use_portable_ops = use_portable_ops
4750

4851
def run(self, artifact: ExecutorchProgramManager, inputs=None) -> None:
4952
super().run(artifact, inputs)
@@ -58,7 +61,7 @@ def run_artifact(self, inputs):
5861
inputs_flattened, _ = tree_flatten(inputs)
5962
intermediate_path = self.compile_spec.get_intermediate_path()
6063
target_board = get_target_board(self.compile_spec)
61-
elf_path = get_elf_path(target_board)
64+
elf_path = get_elf_path(target_board, self.use_portable_ops)
6265

6366
if not os.path.exists(elf_path):
6467
raise FileNotFoundError(

backends/test/suite/flows/arm.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ def _create_arm_flow(
2020
compile_spec: ArmCompileSpec,
2121
symmetric_io_quantization: bool = False,
2222
per_channel_quantization: bool = True,
23+
use_portable_ops: bool = True,
24+
timeout: int = 1200,
2325
) -> TestFlow:
2426

2527
def _create_arm_tester(*args, **kwargs) -> ArmTester:
2628
kwargs["compile_spec"] = compile_spec
27-
return ArmTester(*args, **kwargs)
29+
return ArmTester(
30+
*args, **kwargs, use_portable_ops=use_portable_ops, timeout=timeout
31+
)
2832

2933
support_serialize = not isinstance(compile_spec, TosaCompileSpec)
3034
quantize = compile_spec.tosa_spec.support_integer()

0 commit comments

Comments
 (0)