Skip to content

Commit 1d48089

Browse files
committed
Arm backend: Add tools for finding pte info
- Add devtools/pte_tool/pte_info.py for getting all compile specs from a pte - Add backends/arm/scripts/ethosu_pte_info.py for Ethos-U specific info. - Use ethosu_pte_info.py in build_executor_runner to set default parameters. Signed-off-by: Erik Lundell <erik.lundell@arm.com> Change-Id: I7ce38fb7b103b628ea69730e9380dd628b44caf3
1 parent 2eaa16c commit 1d48089

7 files changed

Lines changed: 613 additions & 4 deletions

File tree

backends/arm/scripts/build_executor_runner.sh

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ _setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly ins
1515
source "${script_dir}/utils.sh"
1616

1717
pte_file=""
18-
target="ethos-u55-128"
18+
target=""
1919
build_type="Release"
2020
bundleio=false
2121
system_config=""
@@ -37,14 +37,15 @@ help() {
3737
echo " --pte=<PTE_FILE>|<ADDR>|semihosting Set to a pte file (generated by the aot_arm_compier) to include the model in the elf."
3838
echo " Or a hex address in the format of 0x00000000 if placed in memory you need to place it on this ADDR on your target, with your flash tool or other means."
3939
echo " Or specify the word 'semihosting' to supply pte at runtime."
40-
echo " --target=<TARGET> Target to build and run for Default: ${target}"
40+
echo " --target=<TARGET> Target to build and run for. Defaults to the PTE Ethos-U compile spec target when available, otherwise ethos-u55-128"
4141
echo " --build_type=<TYPE> Build with Release, Debug or RelWithDebInfo, default is ${build_type}"
4242
echo " --bundleio Support both pte and Bundle IO bpte using Devtools BundelIO with Input/RefOutput included"
43-
echo " --system_config=<CONFIG> System configuration to select from the Vela configuration file (see vela.ini). Default: Ethos_U55_High_End_Embedded for EthosU55 targets, Ethos_U85_SYS_DRAM_Mid for EthosU85 targets."
43+
echo " Defaults to ON when --pte points to a .bpte file."
44+
echo " --system_config=<CONFIG> System configuration to select from the Vela configuration file (see vela.ini). Defaults to the Ethos-U delegate compile spec in the PTE when available, otherwise target-specific defaults."
4445
echo " NOTE: If given, this option must match the given target. This option along with the memory_mode sets timing adapter values customized for specific hardware, see ./executor_runner/CMakeLists.txt."
4546
echo " --memory_mode=<CONFIG> Vela memory mode, used for setting the Timing Adapter parameters of the Corstone platforms."
4647
echo " Valid values are Shared_Sram(for Ethos-U55, Ethos-U65, Ethos-85), Sram_Only(for Ethos-U55, Ethos-U65, Ethos-U85) or Dedicated_Sram(for Ethos-U65, Ethos-U85)."
47-
echo " Default: Shared_Sram for the Ethos-U55 and Sram_Only for the Ethos-U85"
48+
echo " Defaults to the Ethos-U delegate compile spec in the PTE when available, otherwise target-specific defaults."
4849
echo " --etdump Adds Devtools etdump support to track timing and output, etdump area will be base64 encoded in the log"
4950
echo " --extra_build_flags=<FLAGS> Extra flags to pass to cmake like -DET_ARM_BAREMETAL_METHOD_ALLOCATOR_POOL_SIZE=60000 Default: none "
5051
echo " --output=<FOLDER> Output folder Default: <MODEL>/<MODEL>_<TARGET INFO>.pte"
@@ -114,6 +115,9 @@ else
114115
else
115116
echo "PTE included in elf from file ${pte_file}"
116117
pte_file=$(realpath ${pte_file})
118+
if [[ ${pte_file} == *.bpte ]]; then
119+
bundleio=true
120+
fi
117121
pte_data="-DET_PTE_FILE_PATH:PATH=${pte_file}"
118122
if [ "$output_folder_set" = false ] ; then
119123
# remove file ending
@@ -130,6 +134,36 @@ et_build_dir=${et_build_root}/cmake-out
130134
mkdir -p ${et_build_dir}
131135
et_build_dir=$(realpath ${et_build_dir})
132136

137+
# If a PTE file is supplied, derive any unset Ethos-U runtime config from it.
138+
if [[ -f "${pte_file}" ]] && [[ -z "${target}" || -z "${system_config}" || -z "${memory_mode}" ]]; then
139+
set +e
140+
extracted_config=$(python3 "${script_dir}/ethosu_pte_info.py" --format=tsv "${pte_file}")
141+
extracted_status=$?
142+
set -e
143+
144+
if [[ ${extracted_status} -eq 0 ]]; then
145+
IFS=$'\t' read -r extracted_target extracted_system_config extracted_memory_mode <<< "${extracted_config}"
146+
147+
if [[ ${target} == "" ]]; then
148+
target="${extracted_target}"
149+
fi
150+
if [[ ${system_config} == "" ]]; then
151+
system_config="${extracted_system_config}"
152+
fi
153+
if [[ ${memory_mode} == "" ]]; then
154+
memory_mode="${extracted_memory_mode}"
155+
fi
156+
else
157+
echo "Warning: Failed to derive Ethos-U compile spec defaults from ${pte_file}"
158+
fi
159+
fi
160+
161+
# Default values if getting defaults from compile spec failed.
162+
if [[ ${target} == "" ]]
163+
then
164+
target="ethos-u55-128"
165+
fi
166+
133167
if [[ ${system_config} == "" ]]
134168
then
135169
system_config="Ethos_U55_High_End_Embedded"
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2026 Arm Limited and/or its affiliates.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
from __future__ import annotations
9+
10+
import argparse
11+
import json
12+
from dataclasses import asdict, dataclass
13+
from pathlib import Path
14+
15+
from executorch.backends.arm.ethosu import EthosUBackend, EthosUCompileSpec
16+
from executorch.devtools.pte_tool.pte_info import (
17+
DelegateInfo,
18+
get_delegate_infos_from_pte,
19+
)
20+
21+
22+
@dataclass(frozen=True)
23+
class EthosUDelegateConfig:
24+
target: str
25+
system_config: str
26+
memory_mode: str
27+
28+
29+
def _extract_flag_value(flags: list[str], prefix: str) -> str | None:
30+
for flag in flags:
31+
if flag.startswith(prefix):
32+
return flag.removeprefix(prefix)
33+
return None
34+
35+
36+
def _config_from_delegate(delegate_info: DelegateInfo) -> EthosUDelegateConfig:
37+
compile_spec = EthosUCompileSpec._from_list(delegate_info.compile_specs)
38+
if compile_spec.target is None:
39+
raise ValueError("Missing Ethos-U target in delegate compile spec.")
40+
41+
system_config = _extract_flag_value(compile_spec.compiler_flags, "--system-config=")
42+
if system_config is None:
43+
raise ValueError(
44+
f"Missing --system-config flag in Ethos-U compile spec for {compile_spec.target}."
45+
)
46+
47+
memory_mode = _extract_flag_value(compile_spec.compiler_flags, "--memory-mode=")
48+
if memory_mode is None:
49+
raise ValueError(
50+
f"Missing --memory-mode flag in Ethos-U compile spec for {compile_spec.target}."
51+
)
52+
53+
return EthosUDelegateConfig(
54+
target=compile_spec.target,
55+
system_config=system_config,
56+
memory_mode=memory_mode,
57+
)
58+
59+
60+
def get_ethosu_delegate_configs_from_pte(
61+
pte_path: str | Path,
62+
) -> list[EthosUDelegateConfig]:
63+
configs: list[EthosUDelegateConfig] = []
64+
for delegate_info in get_delegate_infos_from_pte(pte_path):
65+
if delegate_info.delegate_id != EthosUBackend.__name__:
66+
continue
67+
configs.append(_config_from_delegate(delegate_info))
68+
return configs
69+
70+
71+
def get_ethosu_delegate_config_from_pte(
72+
pte_path: str | Path,
73+
) -> EthosUDelegateConfig | None:
74+
configs = get_ethosu_delegate_configs_from_pte(pte_path)
75+
if not configs:
76+
return None
77+
78+
unique_configs = sorted(
79+
{
80+
(config.target, config.system_config, config.memory_mode)
81+
for config in configs
82+
}
83+
)
84+
if len(unique_configs) != 1:
85+
joined = ", ".join(
86+
f"target={target} system_config={system_config} memory_mode={memory_mode}"
87+
for target, system_config, memory_mode in unique_configs
88+
)
89+
raise ValueError(
90+
"Found multiple Ethos-U delegate compile spec configurations in "
91+
f"{pte_path}: {joined}"
92+
)
93+
94+
target, system_config, memory_mode = unique_configs[0]
95+
return EthosUDelegateConfig(
96+
target=target,
97+
system_config=system_config,
98+
memory_mode=memory_mode,
99+
)
100+
101+
102+
def _get_args() -> argparse.Namespace:
103+
parser = argparse.ArgumentParser(
104+
description=(
105+
"Read the Ethos-U delegate compile spec from a .pte/.bpte file and "
106+
"print the resolved target, system_config and memory_mode."
107+
)
108+
)
109+
parser.add_argument("pte_path", help="Path to a .pte or .bpte file.")
110+
parser.add_argument(
111+
"--format",
112+
choices=("pretty", "json", "tsv"),
113+
default="pretty",
114+
help="Output format. Default: %(default)s.",
115+
)
116+
return parser.parse_args()
117+
118+
119+
def _print_config(config: EthosUDelegateConfig, output_format: str) -> None:
120+
if output_format == "json":
121+
print(json.dumps(asdict(config), sort_keys=True))
122+
return
123+
if output_format == "tsv":
124+
print(f"{config.target}\t{config.system_config}\t{config.memory_mode}")
125+
return
126+
127+
print(f"target={config.target}")
128+
print(f"system_config={config.system_config}")
129+
print(f"memory_mode={config.memory_mode}")
130+
131+
132+
def main() -> int:
133+
args = _get_args()
134+
config = get_ethosu_delegate_config_from_pte(args.pte_path)
135+
if config is None:
136+
return 2
137+
138+
_print_config(config, args.format)
139+
return 0
140+
141+
142+
if __name__ == "__main__":
143+
raise SystemExit(main())
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Copyright 2026 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+
from executorch.backends.arm.ethosu import EthosUCompileSpec
7+
from executorch.backends.arm.scripts.ethosu_pte_info import (
8+
get_ethosu_delegate_config_from_pte,
9+
)
10+
from executorch.exir._serialize import _PTEFile, _serialize_pte_binary
11+
from executorch.exir.backend.compile_spec_schema import CompileSpec
12+
from executorch.exir.schema import (
13+
BackendDelegate,
14+
BackendDelegateDataReference,
15+
BackendDelegateInlineData,
16+
Buffer,
17+
Chain,
18+
ContainerMetadata,
19+
DataLocation,
20+
ExecutionPlan,
21+
Program,
22+
SubsegmentOffsets,
23+
)
24+
from pytest import raises
25+
26+
27+
def _make_pte_bytes(*, delegates: list[BackendDelegate]) -> bytes:
28+
program = Program(
29+
version=0,
30+
execution_plan=[
31+
ExecutionPlan(
32+
name="forward",
33+
container_meta_type=ContainerMetadata(
34+
encoded_inp_str="[]", encoded_out_str="[]"
35+
),
36+
values=[],
37+
inputs=[],
38+
outputs=[],
39+
chains=[Chain(inputs=[], outputs=[], instructions=[], stacktrace=None)],
40+
operators=[],
41+
delegates=delegates,
42+
non_const_buffer_sizes=[0],
43+
)
44+
],
45+
constant_buffer=[Buffer(storage=b"")],
46+
backend_delegate_data=[BackendDelegateInlineData(data=b"delegate-data")],
47+
segments=[],
48+
constant_segment=SubsegmentOffsets(segment_index=0, offsets=[]),
49+
mutable_data_segments=[],
50+
named_data=[],
51+
)
52+
return bytes(_serialize_pte_binary(_PTEFile(program)))
53+
54+
55+
def _write_pte(tmp_path, *delegates: BackendDelegate):
56+
pte_path = tmp_path / "model.pte"
57+
pte_path.write_bytes(_make_pte_bytes(delegates=list(delegates)))
58+
return pte_path
59+
60+
61+
def _ethosu_delegate(
62+
target: str,
63+
system_config: str,
64+
memory_mode: str,
65+
index: int = 0,
66+
) -> BackendDelegate:
67+
return BackendDelegate(
68+
id="EthosUBackend",
69+
processed=BackendDelegateDataReference(
70+
location=DataLocation.INLINE, index=index
71+
),
72+
compile_specs=EthosUCompileSpec(
73+
target=target,
74+
system_config=system_config,
75+
memory_mode=memory_mode,
76+
)._to_list(),
77+
)
78+
79+
80+
def test_ethosu_pte_info_no_target(tmp_path) -> None:
81+
pte_path = _write_pte(
82+
tmp_path,
83+
_ethosu_delegate(
84+
target="ethos-u85-256",
85+
system_config="Ethos_U85_SYS_DRAM_Mid",
86+
memory_mode="Dedicated_Sram_384KB",
87+
),
88+
)
89+
90+
config = get_ethosu_delegate_config_from_pte(pte_path)
91+
92+
assert config is not None
93+
assert config.target == "ethos-u85-256"
94+
assert config.system_config == "Ethos_U85_SYS_DRAM_Mid"
95+
assert config.memory_mode == "Dedicated_Sram_384KB"
96+
97+
98+
def test_ethosu_pte_info_returns_none_without_ethosu_delegate_no_target(
99+
tmp_path,
100+
) -> None:
101+
pte_path = _write_pte(
102+
tmp_path,
103+
BackendDelegate(
104+
id="OtherBackend",
105+
processed=BackendDelegateDataReference(
106+
location=DataLocation.INLINE, index=0
107+
),
108+
compile_specs=[CompileSpec(key="k", value=b"v")],
109+
),
110+
)
111+
112+
assert get_ethosu_delegate_config_from_pte(pte_path) is None
113+
114+
115+
def test_ethosu_pte_info_rejects_mixed_configs_no_target(tmp_path) -> None:
116+
pte_path = _write_pte(
117+
tmp_path,
118+
_ethosu_delegate(
119+
target="ethos-u55-128",
120+
system_config="Ethos_U55_High_End_Embedded",
121+
memory_mode="Shared_Sram",
122+
),
123+
_ethosu_delegate(
124+
target="ethos-u85-256",
125+
system_config="Ethos_U85_SYS_DRAM_Mid",
126+
memory_mode="Sram_Only",
127+
),
128+
)
129+
130+
with raises(ValueError, match="multiple Ethos-U delegate compile spec"):
131+
get_ethosu_delegate_config_from_pte(pte_path)

devtools/pte_tool/BUCK

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ fbcode_target(_kind = runtime.python_library,
1515
],
1616
)
1717

18+
fbcode_target(_kind = runtime.python_library,
19+
name = "pte_info_lib",
20+
srcs = [
21+
"pte_info.py",
22+
],
23+
deps = [
24+
"//executorch/devtools/bundled_program/serialize:lib",
25+
"//executorch/exir/_serialize:lib",
26+
"//executorch/exir/backend:compile_spec_schema",
27+
],
28+
)
29+
1830
fbcode_target(_kind = runtime.python_binary,
1931
name = "diff_pte",
2032
srcs = [
@@ -27,3 +39,16 @@ fbcode_target(_kind = runtime.python_binary,
2739
"//executorch/exir/_serialize:lib",
2840
],
2941
)
42+
43+
fbcode_target(_kind = runtime.python_binary,
44+
name = "pte_info",
45+
srcs = [
46+
"pte_info.py",
47+
],
48+
main_function = "executorch.devtools.pte_tool.pte_info.main",
49+
deps = [
50+
"//executorch/devtools/bundled_program/serialize:lib",
51+
"//executorch/exir/_serialize:lib",
52+
"//executorch/exir/backend:compile_spec_schema",
53+
],
54+
)

0 commit comments

Comments
 (0)