Skip to content

Commit 7398e1b

Browse files
committed
[runtime] Let Method.execute borrow outputs
Module.forward and the native method take clone_outputs, but the public Method wrapper of executorch.runtime always copied every output, so a caller of the recommended API could not avoid that copy. Method.execute now takes clone_outputs, with the same default and meaning as the bindings: False returns outputs that share the method's memory and may change on the next execution.
1 parent ade59ad commit 7398e1b

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

‎runtime/__init__.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,20 @@ class Method:
136136
def __init__(self, method: ExecuTorchMethod) -> None:
137137
self._method = method
138138

139-
def execute(self, inputs: Sequence[Any]) -> Sequence[Any]:
139+
def execute(
140+
self, inputs: Sequence[Any], clone_outputs: bool = True
141+
) -> Sequence[Any]:
140142
"""Executes the method with the given inputs.
141143
142144
Args:
143145
inputs: A sequence of input values, typically torch.Tensor objects.
146+
clone_outputs: If False, the outputs share the method's memory and
147+
a later execution may overwrite them, which avoids a copy.
144148
145149
Returns:
146150
A list of output values, typically torch.Tensor objects.
147151
"""
148-
return self._method(inputs)
152+
return self._method(inputs, clone_outputs=clone_outputs)
149153

150154
@property
151155
def metadata(self) -> MethodMeta:

‎runtime/test/test_runtime.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ def test_smoke(self):
5252
outputs = method.execute(inputs)
5353
self.assertTrue(torch.allclose(outputs[0], inputs[0] + inputs[1]))
5454

55+
def test_execute_can_borrow_outputs(self):
56+
ep, inputs = create_program(ModuleAdd())
57+
method = Runtime.get().load_program(ep.buffer).load_method("forward")
58+
59+
def address(output):
60+
return torch.from_dlpack(output).data_ptr()
61+
62+
# Borrowed outputs are views of the method's own memory, so each
63+
# execution writes the same place. Cloned outputs are copies.
64+
borrowed = [method.execute(inputs, clone_outputs=False)[0] for _ in range(2)]
65+
self.assertEqual(address(borrowed[0]), address(borrowed[1]))
66+
cloned = [method.execute(inputs)[0] for _ in range(2)]
67+
self.assertNotEqual(address(cloned[0]), address(cloned[1]))
68+
torch.testing.assert_close(
69+
torch.from_dlpack(borrowed[1]), inputs[0] + inputs[1]
70+
)
71+
5572
def test_module_with_multiple_method_names(self):
5673
ep, inputs = create_program(ModuleMulti())
5774
runtime = Runtime.get()

0 commit comments

Comments
 (0)