Skip to content

Commit 7204b6b

Browse files
freddan80per
andcommitted
Move compile spec to ArmTester interface
* Create compile spec builder * Added default compile spec for unit tests Change-Id: Ieae15b213969c703fc0bfcfd99a6a84ae3412676 Signed-off-by: Fredrik Knutsson <[email protected]> Co-authored-by: Per Åstrand <[email protected]>
1 parent 57dd7f1 commit 7204b6b

14 files changed

+389
-310
lines changed

backends/arm/arm_backend.py

Lines changed: 131 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,118 @@
3838
logger.setLevel(logging.INFO)
3939

4040

41+
class ArmCompileSpecBuilder:
42+
def __init__(self):
43+
self.compile_spec: List[CompileSpec] = []
44+
self.compiler_flags = []
45+
self.output_format = None
46+
self.path_for_intermediates = None
47+
self.permute_nhwc = False
48+
49+
def ethosu_compile_spec(
50+
self,
51+
config: str,
52+
system_config: Optional[str] = None,
53+
memory_mode: Optional[str] = None,
54+
extra_flags: Optional[str] = None,
55+
config_ini: Optional[str] = "Arm/vela.ini",
56+
):
57+
"""
58+
Generate compile spec for Ethos-U NPU
59+
60+
Args:
61+
config: Ethos-U accelerator configuration, e.g. ethos-u55-128
62+
system_config: System configuration to select from the Vel
63+
configuration file
64+
memory_mode: Memory mode to select from the Vela configuration file
65+
extra_flags: Extra flags for the Vela compiler
66+
config_ini: Vela configuration file(s) in Python ConfigParser .ini
67+
file format
68+
"""
69+
assert (
70+
self.output_format is None
71+
), f"Output format already set to f{self.output_format}"
72+
self.output_format = "vela"
73+
self.compiler_flags = [
74+
f"--accelerator-config={config}",
75+
f"--config={config_ini}",
76+
]
77+
if system_config is not None:
78+
self.compiler_flags.append(f"--system-config={system_config}")
79+
if memory_mode is not None:
80+
self.compiler_flags.append(f"--memory-mode={memory_mode}")
81+
if extra_flags is not None:
82+
self.compiler_flags.append(extra_flags)
83+
84+
return self
85+
86+
def tosa_compile_spec(self):
87+
"""
88+
Generate compile spec for TOSA flatbuffer output
89+
"""
90+
assert (
91+
self.output_format is None
92+
), f"Output format already set: {self.output_format}"
93+
self.output_format = "tosa"
94+
return self
95+
96+
def dump_intermediate_tosa(self, output_path: str):
97+
"""
98+
Output intermediate .tosa file
99+
"""
100+
self.path_for_intermediates = output_path
101+
return self
102+
103+
def set_permute_memory_format(self, set_nhwc_permutation: bool = True):
104+
self.permute_nhwc = set_nhwc_permutation
105+
return self
106+
107+
def build(self):
108+
"""
109+
Generate a list of compile spec objects from the builder
110+
"""
111+
if self.output_format == "vela":
112+
self.compile_spec += [
113+
CompileSpec("output_format", "vela".encode()),
114+
CompileSpec("compile_flags", " ".join(self.compiler_flags).encode()),
115+
]
116+
elif self.output_format == "tosa":
117+
self.compile_spec.append(CompileSpec("output_format", "tosa".encode()))
118+
119+
if self.path_for_intermediates is not None:
120+
self.compile_spec.append(
121+
CompileSpec("debug_tosa_path", self.path_for_intermediates.encode())
122+
)
123+
124+
if self.permute_nhwc:
125+
self.compile_spec.append(
126+
CompileSpec("permute_memory_format", "nhwc".encode())
127+
)
128+
129+
return self.compile_spec
130+
131+
132+
def is_permute_memory(compile_spec: List[CompileSpec]) -> bool:
133+
for spec in compile_spec:
134+
if spec.key == "permute_memory_format":
135+
return spec.value.decode() == "nhwc"
136+
return False
137+
138+
139+
def is_tosa(compile_spec: List[CompileSpec]) -> bool:
140+
for spec in compile_spec:
141+
if spec.key == "output_format":
142+
return spec.value.decode() == "tosa"
143+
return False
144+
145+
146+
def get_intermediate_path(compile_spec: List[CompileSpec]) -> str:
147+
for spec in compile_spec:
148+
if spec.key == "debug_tosa_path":
149+
return spec.value.decode()
150+
return None
151+
152+
41153
def generate_ethosu_compile_spec(
42154
config: str,
43155
permute_memory_to_nhwc: Optional[bool] = None,
@@ -46,45 +158,31 @@ def generate_ethosu_compile_spec(
46158
extra_flags: Optional[str] = None,
47159
config_ini: Optional[str] = "Arm/vela.ini",
48160
) -> List[CompileSpec]:
49-
"""
50-
Generate compile spec for Ethos-U NPU
51-
"""
52-
compiler_flags = [f"--accelerator-config={config}", f"--config={config_ini}"]
53-
if system_config is not None:
54-
compiler_flags.append(f"--system-config={system_config}")
55-
if memory_mode is not None:
56-
compiler_flags.append(f"--memory-mode={memory_mode}")
57-
if extra_flags is not None:
58-
compiler_flags.append(extra_flags)
59-
60-
compile_spec = [
61-
CompileSpec("output_format", "vela".encode()),
62-
CompileSpec("compile_flags", " ".join(compiler_flags).encode()),
63-
]
64-
65-
if permute_memory_to_nhwc:
66-
compile_spec.append(CompileSpec("permute_memory_format", "nhwc".encode()))
67-
68-
return compile_spec
161+
return (
162+
ArmCompileSpecBuilder()
163+
.ethosu_compile_spec(
164+
config,
165+
system_config=system_config,
166+
memory_mode=memory_mode,
167+
extra_flags=extra_flags,
168+
config_ini=config_ini,
169+
)
170+
.set_permute_memory_format(permute_memory_to_nhwc)
171+
.build()
172+
)
69173

70174

71175
def generate_tosa_compile_spec(
72176
permute_memory_to_nhwc: Optional[bool] = None,
73177
output_path: Optional[str] = None,
74178
) -> List[CompileSpec]:
75-
"""
76-
Generate compile spec for TOSA flatbuffer output
77-
"""
78-
79-
compile_spec = [CompileSpec("output_format", "tosa".encode())]
80-
81-
if permute_memory_to_nhwc:
82-
compile_spec.append(CompileSpec("permute_memory_format", "nhwc".encode()))
83-
84-
if output_path is not None:
85-
compile_spec.append(CompileSpec("debug_tosa_path", output_path.encode()))
86-
87-
return compile_spec
179+
return (
180+
ArmCompileSpecBuilder()
181+
.tosa_compile_spec()
182+
.set_permute_memory_format(permute_memory_to_nhwc)
183+
.dump_intermediate_tosa(output_path)
184+
.build()
185+
)
88186

89187

90188
@final

backends/arm/test/common.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# LICENSE file in the root directory of this source tree.
66

77
import shutil
8+
import tempfile
9+
10+
from executorch.backends.arm.arm_backend import ArmCompileSpecBuilder
811

912
# TODO: fixme! These globs are a temporary workaround. Reasoning:
1013
# Running the jobs in _unittest.yml will not work since that environment doesn't
@@ -13,3 +16,36 @@
1316
# should be installed in the CI env.
1417
TOSA_REF_MODEL_INSTALLED = shutil.which("tosa_reference_model")
1518
VELA_INSTALLED = shutil.which("vela")
19+
20+
21+
def get_tosa_compile_spec(permute_memory_to_nhwc=False, custom_path=None):
22+
"""
23+
Default compile spec for TOSA tests.
24+
"""
25+
intermediate_path = custom_path or tempfile.mkdtemp(prefix="arm_tosa_")
26+
compile_spec = (
27+
ArmCompileSpecBuilder()
28+
.tosa_compile_spec()
29+
.set_permute_memory_format(permute_memory_to_nhwc)
30+
.dump_intermediate_tosa(intermediate_path)
31+
.build()
32+
)
33+
return compile_spec
34+
35+
36+
def get_u55_compile_spec(permute_memory_to_nhwc=False):
37+
"""
38+
Default compile spec for Ethos-U55 tests.
39+
"""
40+
compile_spec = (
41+
ArmCompileSpecBuilder()
42+
.ethosu_compile_spec(
43+
"ethos-u55-128",
44+
system_config="Ethos_U55_High_End_Embedded",
45+
memory_mode="Shared_Sram",
46+
extra_flags=None,
47+
)
48+
.set_permute_memory_format(permute_memory_to_nhwc)
49+
.build()
50+
)
51+
return compile_spec

backends/arm/test/misc/test_debug_feats.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import unittest
1111

1212
import torch
13-
from executorch.backends.arm.test.test_models import TosaProfile
14-
from executorch.backends.arm.test.tester.arm_tester import ArmBackendSelector, ArmTester
13+
from executorch.backends.arm.test import common
14+
15+
from executorch.backends.arm.test.tester.arm_tester import ArmTester
1516

1617
logger = logging.getLogger(__name__)
1718
logger.setLevel(logging.INFO)
@@ -45,8 +46,7 @@ def _tosa_MI_pipeline(self, module: torch.nn.Module, dump_file=None):
4546
ArmTester(
4647
module,
4748
inputs=module.get_inputs(),
48-
profile=TosaProfile.MI,
49-
backend=ArmBackendSelector.TOSA,
49+
compile_spec=common.get_tosa_compile_spec(),
5050
)
5151
.export()
5252
.to_edge()
@@ -60,8 +60,7 @@ def _tosa_BI_pipeline(self, module: torch.nn.Module, dump_file=None):
6060
ArmTester(
6161
module,
6262
inputs=module.get_inputs(),
63-
profile=TosaProfile.BI,
64-
backend=ArmBackendSelector.TOSA,
63+
compile_spec=common.get_tosa_compile_spec(),
6564
)
6665
.quantize()
6766
.export()

backends/arm/test/models/test_mobilenet_v2_arm.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
import torch
1212
import torchvision.models as models
1313
from executorch.backends.arm.test import common
14-
from executorch.backends.arm.test.test_models import TosaProfile
15-
from executorch.backends.arm.test.tester.arm_tester import ArmBackendSelector, ArmTester
14+
15+
from executorch.backends.arm.test.tester.arm_tester import ArmTester
1616
from executorch.backends.xnnpack.test.tester.tester import Quantize
1717
from torchvision.models.mobilenetv2 import MobileNet_V2_Weights
1818

@@ -46,9 +46,7 @@ def test_mv2_tosa_MI(self):
4646
ArmTester(
4747
self.mv2,
4848
inputs=self.model_inputs,
49-
profile=TosaProfile.MI,
50-
backend=ArmBackendSelector.TOSA,
51-
permute_memory_to_nhwc=True,
49+
compile_spec=common.get_tosa_compile_spec(permute_memory_to_nhwc=True),
5250
)
5351
.export()
5452
.to_edge()
@@ -62,9 +60,7 @@ def test_mv2_tosa_BI(self):
6260
ArmTester(
6361
self.mv2,
6462
inputs=self.model_inputs,
65-
profile=TosaProfile.BI,
66-
backend=ArmBackendSelector.TOSA,
67-
permute_memory_to_nhwc=True,
63+
compile_spec=common.get_tosa_compile_spec(permute_memory_to_nhwc=True),
6864
)
6965
.quantize(Quantize(calibrate=False))
7066
.export()
@@ -74,7 +70,7 @@ def test_mv2_tosa_BI(self):
7470
.to_executorch()
7571
)
7672
if common.TOSA_REF_MODEL_INSTALLED:
77-
tester.run_method().compare_outputs()
73+
tester.run_method_and_compare_outputs()
7874
else:
7975
logger.warning(
8076
"TOSA ref model tool not installed, skip numerical correctness tests"
@@ -89,9 +85,7 @@ def test_mv2_u55_BI(self):
8985
ArmTester(
9086
self.mv2,
9187
inputs=self.model_inputs,
92-
profile=TosaProfile.BI,
93-
backend=ArmBackendSelector.ETHOS_U55,
94-
permute_memory_to_nhwc=True,
88+
compile_spec=common.get_u55_compile_spec(permute_memory_to_nhwc=True),
9589
)
9690
.quantize(Quantize(calibrate=False))
9791
.export()

backends/arm/test/ops/test_add.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
import torch
1414
from executorch.backends.arm.test import common
15-
from executorch.backends.arm.test.test_models import TosaProfile
16-
from executorch.backends.arm.test.tester.arm_tester import ArmBackendSelector, ArmTester
15+
16+
from executorch.backends.arm.test.tester.arm_tester import ArmTester
1717
from parameterized import parameterized
1818

1919
logger = logging.getLogger(__name__)
@@ -57,9 +57,7 @@ def _test_add_tosa_MI_pipeline(
5757
ArmTester(
5858
module,
5959
inputs=test_data,
60-
profile=TosaProfile.MI,
61-
backend=ArmBackendSelector.TOSA,
62-
permute_memory_to_nhwc=False,
60+
compile_spec=common.get_tosa_compile_spec(),
6361
)
6462
.export()
6563
.check_count({"torch.ops.aten.add.Tensor": 1})
@@ -70,7 +68,7 @@ def _test_add_tosa_MI_pipeline(
7068
.to_executorch()
7169
)
7270
if common.TOSA_REF_MODEL_INSTALLED:
73-
tester.run_method().compare_outputs()
71+
tester.run_method_and_compare_outputs()
7472
else:
7573
logger.warning(
7674
"TOSA ref model tool not installed, skip numerical correctness tests"
@@ -83,9 +81,7 @@ def _test_add_tosa_BI_pipeline(
8381
ArmTester(
8482
module,
8583
inputs=test_data,
86-
profile=TosaProfile.BI,
87-
backend=ArmBackendSelector.TOSA,
88-
permute_memory_to_nhwc=False,
84+
compile_spec=common.get_tosa_compile_spec(),
8985
)
9086
.quantize()
9187
.export()
@@ -98,7 +94,7 @@ def _test_add_tosa_BI_pipeline(
9894
)
9995

10096
if common.TOSA_REF_MODEL_INSTALLED:
101-
tester.run_method().compare_outputs(qtol=1)
97+
tester.run_method_and_compare_outputs(qtol=1)
10298
else:
10399
logger.warning(
104100
"TOSA ref model tool not installed, skip numerical correctness tests"
@@ -111,8 +107,7 @@ def _test_add_u55_BI_pipeline(
111107
ArmTester(
112108
module,
113109
inputs=test_data,
114-
profile=TosaProfile.BI,
115-
backend=ArmBackendSelector.ETHOS_U55,
110+
compile_spec=common.get_u55_compile_spec(),
116111
)
117112
.quantize()
118113
.export()

0 commit comments

Comments
 (0)