Skip to content

Commit fdd5140

Browse files
authored
Arm backend: Add optional Model Converter debug-info generation. (pytorch#23313)
Add optional Model Converter debug-info generation to the VGF backend. When `emit_debug_info=True` is set in `VgfCompileSpec`, the backend passes: ```text --emit-debug-info ``` to Model Converter. This preserves TOSA debug symbols in the generated VGF and enables future correlation between ExecuTorch `debug_handle`s and VGF operations for profiling. - Add `emit_debug_info` to `VgfCompileSpec`. - Propagate the option through compile-spec serialization. - Pass `--emit-debug-info` to Model Converter when enabled. - Avoid duplicating the flag if it is already present. - Add unit tests for enabled, disabled, and round-trip compile-spec behaviour. The option is disabled by default, so existing VGF compilation behaviour is unchanged. cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani Signed-off-by: Elena Zhelezina <elena.zhelezina@arm.com>
1 parent 64c13a2 commit fdd5140

6 files changed

Lines changed: 103 additions & 3 deletions

File tree

‎backends/arm/public_api_manifests/api_manifest_running.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ signature = "VgfBackend.preprocess(edge_program: torch.export.exported_program.E
138138

139139
[python.VgfCompileSpec]
140140
kind = "class"
141-
signature = "VgfCompileSpec(tosa_spec: executorch.backends.arm.tosa.specification.TosaSpecification | str | None = None, compiler_flags: list[str] | None = None)"
141+
signature = "VgfCompileSpec(tosa_spec: executorch.backends.arm.tosa.specification.TosaSpecification | str | None = None, compiler_flags: list[str] | None = None, emit_debug_info: bool = False)"
142142

143143
[python.VgfCompileSpec.DebugMode]
144144
kind = "enum"

‎backends/arm/test/misc/test_compile_spec.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ def test_preserve_tosa_dev_mode_roundtrip_vgf_FP_INT():
127127
assert roundtripped.tosa_dev_mode is True
128128

129129

130+
def test_emit_debug_info_roundtrip_vgf_FP_INT():
131+
disabled = VgfCompileSpec()
132+
disabled_roundtripped = VgfCompileSpec._from_list(disabled._to_list())
133+
assert disabled_roundtripped.emit_debug_info is False
134+
135+
enabled = VgfCompileSpec(emit_debug_info=True)
136+
enabled_roundtripped = VgfCompileSpec._from_list(enabled._to_list())
137+
assert enabled_roundtripped.emit_debug_info is True
138+
139+
130140
def test_preserve_io_quantization_warns_for_u55_INT():
131141
with warns(
132142
UserWarning,

‎backends/arm/test/misc/test_vgf_backend.py‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,66 @@ def _raise(*args, **kwargs):
117117
clear_registered_pass_insertions()
118118

119119

120+
def test_compile_tosa_flatbuffer_does_not_emit_debug_info_by_default(
121+
monkeypatch,
122+
) -> None:
123+
captured_flags = None
124+
125+
def fake_vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name):
126+
nonlocal captured_flags
127+
captured_flags = list(compile_flags)
128+
return b"vgf"
129+
130+
monkeypatch.setattr(vgf_backend, "vgf_compile", fake_vgf_compile)
131+
132+
result = vgf_backend.VgfBackend._compile_tosa_flatbuffer(
133+
b"tosa", VgfCompileSpec(compiler_flags=["--existing-flag"])
134+
)
135+
136+
assert result == b"vgf"
137+
assert captured_flags == ["--existing-flag"]
138+
139+
140+
def test_compile_tosa_flatbuffer_emits_debug_info_when_enabled(monkeypatch) -> None:
141+
captured_flags = None
142+
143+
def fake_vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name):
144+
nonlocal captured_flags
145+
captured_flags = list(compile_flags)
146+
return b"vgf"
147+
148+
monkeypatch.setattr(vgf_backend, "vgf_compile", fake_vgf_compile)
149+
150+
result = vgf_backend.VgfBackend._compile_tosa_flatbuffer(
151+
b"tosa",
152+
VgfCompileSpec(compiler_flags=["--existing-flag"], emit_debug_info=True),
153+
)
154+
155+
assert result == b"vgf"
156+
assert captured_flags == ["--existing-flag", "--emit-debug-info"]
157+
158+
159+
def test_compile_tosa_flatbuffer_does_not_duplicate_emit_debug_info(
160+
monkeypatch,
161+
) -> None:
162+
captured_flags = None
163+
164+
def fake_vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name):
165+
nonlocal captured_flags
166+
captured_flags = list(compile_flags)
167+
return b"vgf"
168+
169+
monkeypatch.setattr(vgf_backend, "vgf_compile", fake_vgf_compile)
170+
171+
result = vgf_backend.VgfBackend._compile_tosa_flatbuffer(
172+
b"tosa",
173+
VgfCompileSpec(compiler_flags=["--emit-debug-info"], emit_debug_info=True),
174+
)
175+
176+
assert result == b"vgf"
177+
assert captured_flags == ["--emit-debug-info"]
178+
179+
120180
def test_format_repro_command_quotes_shell_metacharacters():
121181
command = [
122182
"model-converter",

‎backends/arm/vgf/backend.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ def _compile_tosa_flatbuffer(
209209
bytes: Target-specific VGF binary stream.
210210
211211
"""
212-
compile_flags = compile_spec.compiler_flags
212+
compile_flags = list(compile_spec.compiler_flags)
213+
if compile_spec.emit_debug_info and "--emit-debug-info" not in compile_flags:
214+
compile_flags.append("--emit-debug-info")
213215
artifact_path = compile_spec._get_intermediate_path()
214216
# Pass on the TOSA flatbuffer to the vgf compiler.
215217
binary = vgf_compile(tosa_flatbuffer, compile_flags, artifact_path, tag_name)

‎backends/arm/vgf/compile_spec.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec
1010
from executorch.backends.arm.tosa import TosaSpecification
11+
from executorch.exir.backend.compile_spec_schema import CompileSpec
1112

1213
if TYPE_CHECKING:
1314
from executorch.backends.arm.vgf.check_env import VgfEnvironmentReport
@@ -24,13 +25,18 @@ class VgfCompileSpec(ArmCompileSpec):
2425
target. Strings are parsed via ``TosaSpecification.create_from_string``.
2526
Defaults to ``"TOSA-1.0+FP+INT+int4+int16"``.
2627
compiler_flags (list[str] | None): Optional converter-backend flags.
28+
emit_debug_info (bool): Preserve Model Converter debug information in
29+
the generated VGF. Defaults to ``False``.
2730
2831
"""
2932

33+
_EMIT_DEBUG_INFO_KEY = "vgf_emit_debug_info"
34+
3035
def __init__(
3136
self,
3237
tosa_spec: TosaSpecification | str | None = None,
3338
compiler_flags: list[str] | None = None,
39+
emit_debug_info: bool = False,
3440
):
3541
if tosa_spec is None:
3642
tosa_spec = TosaSpecification.create_from_string(
@@ -42,12 +48,32 @@ def __init__(
4248
if compiler_flags is None:
4349
compiler_flags = []
4450
self._set_compile_specs(tosa_spec, compiler_flags)
51+
self.emit_debug_info = emit_debug_info
4552
# intermediate handling needed until release 2027.02 of tosa-tools
4653
self._set_tosa_dev_mode(True)
4754
self._validate()
4855

56+
def _to_list(self):
57+
"""Return compile specs including the VGF debug-info setting."""
58+
compile_specs = super()._to_list()
59+
if self.emit_debug_info:
60+
compile_specs.append(CompileSpec(self._EMIT_DEBUG_INFO_KEY, b"True"))
61+
return compile_specs
62+
63+
@classmethod
64+
def _from_list_hook(cls, compile_spec, specs: dict[str, str]):
65+
"""Restore VGF-specific settings from serialized compile specs."""
66+
emit_debug_info = specs.get(cls._EMIT_DEBUG_INFO_KEY)
67+
compile_spec.emit_debug_info = (
68+
str(emit_debug_info).lower() in ("1", "true", "yes")
69+
if emit_debug_info is not None
70+
else False
71+
)
72+
4973
def _validate(self):
5074
"""Validate the configuration against VGF-supported TOSA profiles."""
75+
if type(self.emit_debug_info) is not bool:
76+
raise ValueError("emit_debug_info must be a bool.")
5177
tosa_version = self.tosa_spec.version # type: ignore[attr-defined]
5278
tosa_profiles = self.tosa_spec.profiles # type: ignore[attr-defined]
5379

‎docs/source/backends/arm-vgf/arm-vgf-overview.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ To extract the VGF file for integration into applications without the ExecuTorch
4141
The full user-facing API is documented below.
4242

4343
```python
44-
class VgfCompileSpec(tosa_spec: executorch.backends.arm.tosa.specification.TosaSpecification | str | None = None, compiler_flags: list[str] | None = None)
44+
class VgfCompileSpec(tosa_spec: executorch.backends.arm.tosa.specification.TosaSpecification | str | None = None, compiler_flags: list[str] | None = None, emit_debug_info: bool = False)
4545
```
4646
Normalise inputs and populate the underlying Arm compile spec.
4747

@@ -50,6 +50,8 @@ Args:
5050
target. Strings are parsed via ``TosaSpecification.create_from_string``.
5151
Defaults to ``"TOSA-1.0+FP+INT+int4+int16"``.
5252
- **compiler_flags (list[str] | None)**: Optional converter-backend flags.
53+
- **emit_debug_info (bool)**: Preserve Model Converter debug information in
54+
the generated VGF. Defaults to ``False``.
5355

5456
```python
5557
def VgfCompileSpec.dump_debug_info(self, debug_mode: executorch.backends.arm.common.arm_compile_spec.ArmCompileSpec.DebugMode | None):

0 commit comments

Comments
 (0)