Skip to content

Commit 3f686b9

Browse files
author
ssjia
committed
Update on "[ET-VK] Show stack trace in Exception messages via boost if boost is available"
Title says it all! To enable easier debugging, use boost::stracktrace (if available) to record stack traces when throwing an Exception. This is available only when building for a host machine. Differential Revision: [D84262869](https://our.internmc.facebook.com/intern/diff/D84262869/) [ghstack-poisoned]
2 parents b147170 + 49af8bd commit 3f686b9

File tree

17 files changed

+245
-80
lines changed

17 files changed

+245
-80
lines changed

backends/arm/_passes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .convert_to_clamp import ConvertToClampPass # noqa
2828
from .decompose_acosh_pass import DecomposeAcoshPass # noqa
2929
from .decompose_adaptive_avg_pool2d_pass import DecomposeAdaptiveAvgPool2dPass # noqa
30+
from .decompose_add_sub_alpha_pass import DecomposeAddSubAlphaPass # noqa
3031
from .decompose_addmm_pass import DecomposeAddmmPass # noqa
3132
from .decompose_asin_and_acos_pass import DecomposeAsinAndAcosPass # noqa
3233
from .decompose_asinh_pass import DecomposeAsinhPass # noqa

backends/arm/_passes/arm_pass_manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
DecomposeAcoshPass,
3737
DecomposeAdaptiveAvgPool2dPass,
3838
DecomposeAddmmPass,
39+
DecomposeAddSubAlphaPass,
3940
DecomposeAsinAndAcosPass,
4041
DecomposeAsinhPass,
4142
DecomposeAtanhPass,
@@ -262,6 +263,7 @@ def _tosa_FP_pipeline(self, exported_program: ExportedProgram) -> GraphModule:
262263
)
263264
self.add_pass(DecomposeNotEqualPass())
264265
self.add_pass(DecomposeDivPass())
266+
self.add_pass(DecomposeAddSubAlphaPass())
265267
self.add_pass(DecomposeSoftmaxPass())
266268
self.add_pass(DecomposeGeluPass())
267269
self.add_pass(ConvertFullLikeToFullPass())
@@ -334,6 +336,7 @@ def transform_for_annotation_pipeline(self, graph_module: GraphModule):
334336
self.add_pass(DecomposeSignPass())
335337
self.add_pass(DecomposeAddmmPass())
336338
self.add_pass(DecomposeDivTensorModePass())
339+
self.add_pass(DecomposeAddSubAlphaPass())
337340
self.add_pass(ReplaceScalarWithTensorArgPassTOSABI())
338341
self.add_pass(ScalarsToAttributePass())
339342
self.add_pass(DecomposeGroupNormPass())
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Copyright 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+
from __future__ import annotations
7+
8+
import numbers
9+
from typing import Set, Type
10+
11+
import torch
12+
from executorch.backends.arm._passes import ArmPass
13+
from executorch.exir.dialects._ops import ops as exir_ops
14+
from executorch.exir.pass_base import ExportPass
15+
16+
17+
_ADD_OPS = (
18+
exir_ops.edge.aten.add.Tensor,
19+
torch.ops.aten.add.Tensor,
20+
)
21+
22+
_SUB_OPS = (
23+
exir_ops.edge.aten.sub.Tensor,
24+
torch.ops.aten.sub.Tensor,
25+
)
26+
27+
28+
def _get_ops(op):
29+
if op in _ADD_OPS:
30+
if op is exir_ops.edge.aten.add.Tensor:
31+
return (
32+
exir_ops.edge.aten.mul.Tensor,
33+
exir_ops.edge.aten.full.default,
34+
exir_ops.edge.aten.add.Tensor,
35+
)
36+
return (
37+
torch.ops.aten.mul.Tensor,
38+
torch.ops.aten.full.default,
39+
torch.ops.aten.add.Tensor,
40+
)
41+
if op in _SUB_OPS:
42+
if op is exir_ops.edge.aten.sub.Tensor:
43+
return (
44+
exir_ops.edge.aten.mul.Tensor,
45+
exir_ops.edge.aten.full.default,
46+
exir_ops.edge.aten.sub.Tensor,
47+
)
48+
return (
49+
torch.ops.aten.mul.Tensor,
50+
torch.ops.aten.full.default,
51+
torch.ops.aten.sub.Tensor,
52+
)
53+
raise RuntimeError(f"Unsupported operator {op}")
54+
55+
56+
def _should_decompose(alpha) -> bool:
57+
if isinstance(alpha, numbers.Number):
58+
return alpha != 1
59+
return False
60+
61+
62+
class DecomposeAddSubAlphaPass(ArmPass):
63+
"""Rewrite add/sub with alpha into a mul followed by add/sub."""
64+
65+
_passes_required_after: Set[Type[ExportPass]] = set()
66+
67+
def call_operator(self, op, args, kwargs, meta, updated: bool | None = False):
68+
if op not in _ADD_OPS + _SUB_OPS:
69+
return super().call_operator(op, args, kwargs, meta, updated)
70+
71+
alpha = kwargs.get("alpha", 1)
72+
if not _should_decompose(alpha):
73+
return super().call_operator(op, args, kwargs, meta, updated)
74+
75+
mul_op, full_op, binary_op = _get_ops(op)
76+
lhs, rhs = args
77+
78+
alpha_full = super().call_operator(
79+
full_op, ((1,), float(alpha)), {}, meta, updated=True
80+
)
81+
scaled_rhs = super().call_operator(
82+
mul_op,
83+
(rhs, alpha_full),
84+
{},
85+
meta,
86+
updated=True,
87+
)
88+
return super().call_operator(
89+
binary_op,
90+
(lhs, scaled_rhs),
91+
{},
92+
meta,
93+
updated=True,
94+
)

backends/arm/runtime/VGFSetup.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ namespace vgf {
2424
/* static function to map format to byte count */
2525
static uint32_t get_format_size(VkFormat format);
2626

27+
// SPV_ARM_tensor does not support rank-0 representations according to the spec.
28+
// Use an unsqueezed dimension when the resource table contains an empty
29+
// shape. Tensors are output as rank 0 when copied back from the vgf backend.
30+
namespace {
31+
constexpr int64_t kScalarSentinelDimension = 1;
32+
}
33+
2734
// Debug function to inspect memory properties
2835
static string memory_flags_to_string(VkMemoryPropertyFlags flags) {
2936
if (flags == 0)
@@ -264,7 +271,11 @@ static void debug_print_resources(
264271
the_shape.size(),
265272
the_stride.size());
266273
for (int j = 0; j < the_shape.size(); j++) {
267-
ET_LOG(Info, " %d: dim %ld", j, the_shape[j]);
274+
ET_LOG(
275+
Info,
276+
" %d: dim %lld",
277+
j,
278+
static_cast<long long>(the_shape[j]));
268279
}
269280
// Allocate a tensor with bound memory
270281
break;
@@ -387,6 +398,7 @@ bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef<CompileSpec> specs) {
387398
// Get tensor shape and strides
388399
auto shape = resource_decoder->getTensorShape(i);
389400
auto stride = resource_decoder->getTensorStride(i);
401+
const auto shape_size = shape.size();
390402

391403
switch (resource_decoder->getCategory(i)) {
392404
case vgflib::ResourceCategory::INPUT:
@@ -409,9 +421,9 @@ bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef<CompileSpec> specs) {
409421
result = allocate_tensor(
410422
vk_physical,
411423
vk_device,
412-
vgflib::ToVkFormat(resource_decoder->getVkFormat(i)),
413-
static_cast<uint32_t>(shape.size()),
414-
shape.begin(),
424+
resource_format,
425+
shape_size == 0 ? 1 : static_cast<uint32_t>(shape_size),
426+
shape_size == 0 ? &kScalarSentinelDimension : shape.begin(),
415427
static_cast<uint32_t>(stride.size()),
416428
stride.begin(),
417429
&tensor_description,
@@ -422,8 +434,7 @@ bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef<CompileSpec> specs) {
422434
ET_LOG(Error, "Failed to allocate tensor for VGF resource %d", i);
423435
return false;
424436
}
425-
size_t e_size = get_format_size(
426-
vgflib::ToVkFormat(resource_decoder->getVkFormat(i)));
437+
size_t e_size = get_format_size(resource_format);
427438
if (0 == e_size) {
428439
ET_LOG(Error, "failed to get element size of VkFormat");
429440
return false;
@@ -449,9 +460,11 @@ bool VgfRepr::process_vgf(const char* vgf_data, ArrayRef<CompileSpec> specs) {
449460
.sType = VK_STRUCTURE_TYPE_TENSOR_DESCRIPTION_ARM,
450461
.pNext = nullptr,
451462
.tiling = VK_TENSOR_TILING_LINEAR_ARM,
452-
.format = vgflib::ToVkFormat(resource_decoder->getVkFormat(i)),
453-
.dimensionCount = static_cast<uint32_t>(shape.size()),
454-
.pDimensions = shape.begin(),
463+
.format = resource_format,
464+
.dimensionCount =
465+
shape_size == 0 ? 1 : static_cast<uint32_t>(shape_size),
466+
.pDimensions =
467+
shape_size == 0 ? &kScalarSentinelDimension : shape.begin(),
455468
// Note: stride_data of 0's causes size==0, null means stride==size
456469
.pStrides = (0 == stride.size() ? nullptr : stride.begin()),
457470
.usage = VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM,

backends/arm/test/ops/test_add.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def forward(self, x: torch.Tensor, y: torch.Tensor):
7878

7979
class Add3(torch.nn.Module):
8080
def forward(self, x: torch.Tensor, y: torch.Tensor):
81-
return x + y
81+
return torch.add(x, y, alpha=1.5)
8282

8383
test_data: list[input_t2] = {
8484
"3d_randn_diff_rank": lambda: (torch.randn(1, 4, 5), torch.randn(4, 1)),

backends/arm/test/ops/test_addmm.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ def test_addmm_u85_INT(test_data: Tuple):
167167

168168
@common.parametrize("test_data", test_data_suite)
169169
@common.SkipIfNoModelConverter
170-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
171170
def test_addmm_vgf_FP(test_data: input_t1):
172171
pipeline = VgfPipeline[input_t1](
173172
Addmm(),
@@ -181,7 +180,6 @@ def test_addmm_vgf_FP(test_data: input_t1):
181180

182181
@common.parametrize("test_data", test_data_suite)
183182
@common.SkipIfNoModelConverter
184-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
185183
def test_addmm_vgf_INT(test_data: input_t1):
186184
pipeline = VgfPipeline[input_t1](
187185
Addmm(),

backends/arm/test/ops/test_amax.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ def test_max_dim_tosa_FP_not_delegated():
139139

140140
@common.parametrize("test_data", Amax.test_data)
141141
@common.SkipIfNoModelConverter
142-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
143142
def test_amax_vgf_FP(test_data: Amax.input_t):
144143
data, dim, keep_dims = test_data()
145144
module = Amax(dim, keep_dims)
@@ -154,7 +153,6 @@ def test_amax_vgf_FP(test_data: Amax.input_t):
154153

155154
@common.parametrize("test_data", Amax.test_data)
156155
@common.SkipIfNoModelConverter
157-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
158156
def test_amax_vgf_INT(test_data: Amax.input_t):
159157
data, dim, keep_dims = test_data()
160158
module = Amax(dim, keep_dims)
@@ -169,7 +167,6 @@ def test_amax_vgf_INT(test_data: Amax.input_t):
169167

170168
@common.parametrize("test_data", Max.test_data)
171169
@common.SkipIfNoModelConverter
172-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
173170
def test_max_dim_vgf_FP_to_amax(test_data: Max.input_t):
174171
data, dim = test_data()
175172
pipeline = VgfPipeline[Max.input_t](
@@ -183,7 +180,6 @@ def test_max_dim_vgf_FP_to_amax(test_data: Max.input_t):
183180

184181
@common.parametrize("test_data", Max.test_data)
185182
@common.SkipIfNoModelConverter
186-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
187183
def test_max_dim_vgf_INT_to_amax(test_data: Max.input_t):
188184
data, dim = test_data()
189185
pipeline = VgfPipeline[Max.input_t](

backends/arm/test/ops/test_amin.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ def test_min_dim_tosa_FP_not_delegated():
155155

156156
@common.parametrize("test_data", Amin.test_data)
157157
@common.SkipIfNoModelConverter
158-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
159158
def test_amin_vgf_FP(test_data: Amin.input_t):
160159
data, dim, keep_dims = test_data()
161160
pipeline = VgfPipeline[Amin.input_t](
@@ -166,7 +165,6 @@ def test_amin_vgf_FP(test_data: Amin.input_t):
166165

167166
@common.parametrize("test_data", Amin.test_data)
168167
@common.SkipIfNoModelConverter
169-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
170168
def test_amin_vgf_INT(test_data: Amin.input_t):
171169
data, dim, keep_dims = test_data()
172170
pipeline = VgfPipeline[Amin.input_t](
@@ -180,7 +178,6 @@ def test_amin_vgf_INT(test_data: Amin.input_t):
180178

181179
@common.parametrize("test_data", Min.test_data)
182180
@common.SkipIfNoModelConverter
183-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
184181
def test_min_dim_vgf_FP_to_amin(test_data: Min.input_t):
185182
data, dim = test_data()
186183
pipeline = VgfPipeline[Min.input_t](
@@ -194,7 +191,6 @@ def test_min_dim_vgf_FP_to_amin(test_data: Min.input_t):
194191

195192
@common.parametrize("test_data", Min.test_data)
196193
@common.SkipIfNoModelConverter
197-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
198194
def test_min_dim_vgf_INT_to_amin(test_data: Min.input_t):
199195
data, dim = test_data()
200196
pipeline = VgfPipeline[Min.input_t](

backends/arm/test/ops/test_any.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from typing import List, Tuple
88

9-
import pytest
109
import torch
1110
from executorch.backends.arm.test import common
1211
from executorch.backends.arm.test.tester.test_pipeline import (
@@ -189,7 +188,6 @@ def test_any_u85_INT(test_data: input_t1):
189188

190189
@common.parametrize("test_data", test_data)
191190
@common.SkipIfNoModelConverter
192-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
193191
def test_any_vgf_FP(test_data: input_t1):
194192
op, data_fn = test_data()
195193
pipeline = VgfPipeline[input_t1](
@@ -204,7 +202,6 @@ def test_any_vgf_FP(test_data: input_t1):
204202

205203
@common.parametrize("test_data", test_data)
206204
@common.SkipIfNoModelConverter
207-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
208205
def test_any_vgf_INT(test_data: input_t1):
209206
op, data_fn = test_data()
210207
pipeline = VgfPipeline[input_t1](

backends/arm/test/ops/test_mean_dim.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#
55
# This source code is licensed under the BSD-style license found in the
66
# LICENSE file in the root directory of this source tree.
7-
import pytest
87
import torch
98
from executorch.backends.arm.test import common
109
from executorch.backends.arm.test.tester.test_pipeline import (
@@ -84,7 +83,6 @@ def test_adaptive_avg_pool2d_u85_INT(test_data):
8483

8584
@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite)
8685
@common.SkipIfNoModelConverter
87-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
8886
def test_adaptive_avg_pool2d_vgf_FP(test_data):
8987
pipeline = VgfPipeline[input_t](
9088
AdaptiveAveragePool2d(),
@@ -98,7 +96,6 @@ def test_adaptive_avg_pool2d_vgf_FP(test_data):
9896

9997
@common.parametrize("test_data", AdaptiveAveragePool2d.test_data_suite)
10098
@common.SkipIfNoModelConverter
101-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
10299
def test_adaptive_avg_pool2d_vgf_INT(test_data):
103100
pipeline = VgfPipeline[input_t](
104101
AdaptiveAveragePool2d(),
@@ -331,7 +328,6 @@ def test_mean_dim_u85_INT(test_data):
331328

332329
@common.parametrize("test_data", MeanDim.test_data_suite)
333330
@common.SkipIfNoModelConverter
334-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
335331
def test_mean_dim_vgf_FP(test_data):
336332
test_data_val, dim, keep_dim = test_data()
337333
pipeline = VgfPipeline[input_t](
@@ -346,7 +342,6 @@ def test_mean_dim_vgf_FP(test_data):
346342

347343
@common.parametrize("test_data", MeanDim.test_data_suite)
348344
@common.SkipIfNoModelConverter
349-
@pytest.mark.xfail(reason="MLETORCH-1410: Tensor dimension count not supported: 0")
350345
def test_mean_dim_vgf_INT(test_data):
351346
test_data_val, dim, keep_dim = test_data()
352347
pipeline = VgfPipeline[input_t](

0 commit comments

Comments
 (0)