Skip to content

Commit fd5069d

Browse files
authored
Fix test_serialization CI import failure (pytorch#23002)
Summary: The new `test_mutation_aliasing_user_output_gets_one_slot` imported `VulkanPartitioner` and `to_edge_transform_and_lower`, but the `test_serialization` target only depends on `torch` and `vulkan_preprocess`. The import raised `ModuleNotFoundError` at module load, fataling all 9 tests in the file with "test passed but the binary exited with a non-zero exit code". Rewrote the test in the existing synthetic style used in the file (`VkGraphBuilder` over a `SimpleNamespace` program, no lowering), covering alias on/off with and without `output_specs`, and added `test_duplicate_user_outputs_get_two_slots` for the duplicate-output serialization fix Differential Revision: D121213285
1 parent 17fe76d commit fd5069d

1 file changed

Lines changed: 66 additions & 38 deletions

File tree

‎backends/vulkan/test/test_serialization.py‎

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import executorch.backends.vulkan.custom_ops_lib # noqa: F401
1616
import torch
17-
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
1817
from executorch.backends.vulkan.serialization import (
1918
vulkan_graph_builder as graph_builder_module,
2019
)
@@ -35,7 +34,7 @@
3534
serialize_vulkan_graph,
3635
VulkanDelegateHeader,
3736
)
38-
from executorch.exir import to_edge_transform_and_lower
37+
from torch.export.graph_signature import OutputKind
3938

4039

4140
class TestSerialization(unittest.TestCase):
@@ -175,42 +174,71 @@ def test_mutation_aliasing_user_output_gets_one_slot(self) -> None:
175174
# the mutation and the user output are the same node. With aliasing on
176175
# the mutation is applied in place and only the user output takes a
177176
# slot; without it the mutation still needs a slot to carry the new
178-
# value back, and the graph is left to be rejected rather than silently
179-
# skipping the state update.
180-
class Model(torch.nn.Module):
181-
def __init__(self) -> None:
182-
super().__init__()
183-
self.register_buffer("state", torch.zeros(2, 48))
184-
185-
def forward(self, x):
186-
self.state.add_(x)
187-
return self.state.view(2, 48)
188-
189-
for alias, expected_slots in ((True, 1), (False, 2)):
190-
with self.subTest(alias_buffer_mutations=alias):
191-
captured: List[int] = []
192-
original = graph_builder_module.VkGraphBuilder.build_graph
193-
194-
def spy(builder_self, _original=original, _captured=captured):
195-
graph = _original(builder_self)
196-
_captured.append(len(graph.output_ids))
197-
return graph
198-
199-
graph_builder_module.VkGraphBuilder.build_graph = spy
200-
try:
201-
program = torch.export.export(
202-
Model(), (torch.ones(2, 48),), strict=True
203-
)
204-
to_edge_transform_and_lower(
205-
program,
206-
partitioner=[
207-
VulkanPartitioner({"alias_buffer_mutations": alias})
208-
],
209-
).to_executorch()
210-
finally:
211-
graph_builder_module.VkGraphBuilder.build_graph = original
212-
213-
self.assertEqual(captured, [expected_slots])
177+
# value back.
178+
for prepack in (False, True):
179+
for with_specs in (False, True):
180+
program, _, mutation, _ = self._build_mutation_program(
181+
prepack, shared_user_output=True
182+
)
183+
if with_specs:
184+
program.graph_signature.output_specs = [
185+
SimpleNamespace(kind=OutputKind.BUFFER_MUTATION),
186+
SimpleNamespace(kind=OutputKind.USER_OUTPUT),
187+
]
188+
for alias, expected_slots in ((True, 1), (False, 2)):
189+
with self.subTest(
190+
prepack=prepack,
191+
output_specs=with_specs,
192+
alias_buffer_mutations=alias,
193+
):
194+
builder = graph_builder_module.VkGraphBuilder(
195+
program,
196+
graph_builder_module.DelegateMappingBuilder(
197+
generated_identifiers=True
198+
),
199+
alias_buffer_mutations=alias,
200+
)
201+
graph = builder.build_graph()
202+
self.assertEqual(
203+
graph.output_ids,
204+
[builder.node_to_value_ids[mutation]] * expected_slots,
205+
)
206+
207+
def test_duplicate_user_outputs_get_two_slots(self) -> None:
208+
# `Node.all_input_nodes` de-duplicates, so a graph returning the same
209+
# value twice must still serialize one output id per output, or the
210+
# runtime's argument count check fails.
211+
graph = torch.fx.Graph()
212+
user_input = graph.placeholder("user_input")
213+
user_input.meta["spec"] = graph_builder_module.TensorSpec.from_tensor(
214+
torch.ones(4)
215+
)
216+
output = graph.call_function(torch.ops.aten.mul.Tensor, (user_input, 2.0))
217+
output.meta["spec"] = graph_builder_module.TensorSpec.from_tensor(torch.ones(4))
218+
graph.output((output, output))
219+
220+
program = SimpleNamespace(
221+
constants={},
222+
graph_module=torch.fx.GraphModule({}, graph),
223+
graph_signature=SimpleNamespace(
224+
buffers_to_mutate={},
225+
inputs_to_buffers={},
226+
inputs_to_lifted_tensor_constants={},
227+
inputs_to_parameters={},
228+
non_persistent_buffers=set(),
229+
user_outputs=(output.name, output.name),
230+
),
231+
state_dict={},
232+
)
233+
builder = graph_builder_module.VkGraphBuilder(
234+
program,
235+
graph_builder_module.DelegateMappingBuilder(generated_identifiers=True),
236+
)
237+
vk_graph = builder.build_graph()
238+
self.assertEqual(
239+
vk_graph.output_ids,
240+
[builder.node_to_value_ids[output]] * 2,
241+
)
214242

215243
def _generate_random_const_tensors(self, num_tensors: int) -> List[torch.Tensor]:
216244
"""

0 commit comments

Comments
 (0)