Elide redundant same-device copies in PropagateDevicePass (#20914)#20914
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/20914
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit 44fea49 with merge base e500fee ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
@Conarnar has exported this pull request. If you are a Meta employee, you can view the originating Diff in D111992997. |
This PR needs a
|
There was a problem hiding this comment.
Pull request overview
This PR improves PropagateDevicePass by removing redundant host/device transfer pairs that occur when two delegated regions execute back-to-back on the same device, avoiding an unnecessary device→host→device round-trip while preserving true cross-device transfers.
Changes:
- Add a third phase to
PropagateDevicePassthat detects and elides_h2d_copy(_d2h_copy(x))whenxis already on the same target device. - Add targeted tests that construct two consecutive delegates with per-op target devices and verify redundant same-device copies are removed while cross-device copies remain.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
exir/passes/propagate_device_pass.py |
Adds an optimization pass phase to remove redundant same-device D2H→H2D copy chains after per-boundary copy insertion. |
exir/tests/test_propagate_device_pass.py |
Adds a custom partitioner to force per-add delegation and two tests validating same-device elision and cross-device preservation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Differential Revision: D111992997
9e4ab31 to
ce30c8b
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Differential Revision: D111992997
ce30c8b to
7c91a10
Compare
7c91a10 to
b2d7712
Compare
b2d7712 to
596c42e
Compare
596c42e to
e07e470
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Differential Revision: D111992997
e07e470 to
0ae723a
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Differential Revision: D111992997
0ae723a to
ec7ba46
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Differential Revision: D111992997
ec7ba46 to
4d2005a
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Reviewed By: Gasoonjia Differential Revision: D111992997
4d2005a to
27d4f20
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Reviewed By: Gasoonjia Differential Revision: D111992997
27d4f20 to
6510082
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Reviewed By: Gasoonjia Differential Revision: D111992997
6510082 to
8422b8e
Compare
) Summary: PropagateDevicePass inserts H2D/D2H copies per delegate boundary independently (an H2D before every device delegate input, a D2H after every device delegate output). When two delegates run consecutively on the *same* device, this leaves a redundant device -> host -> device round-trip between them: the first delegate's output is copied to host and immediately copied back to the same device for the second delegate. This adds a third phase to PropagateDevicePass that elides `_h2d_copy(_d2h_copy(x))` when the tensor before the D2H already lives on the device the H2D copies back to. The device comparison is the correctness guard: a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing devices and is preserved. A D2H that still feeds other (host) consumers keeps those users and is removed only once it becomes dead. The phase runs only when enable_non_cpu_memory_planning is set (i.e. when copies were actually inserted). This closes the "redundant copies between back-to-back delegates on the same device" limitation from the device-aware export work. Reviewed By: Gasoonjia Differential Revision: D111992997
8422b8e to
44fea49
Compare
Summary:
PropagateDevicePass inserts H2D/D2H copies per delegate boundary
independently (an H2D before every device delegate input, a D2H after every
device delegate output). When two delegates run consecutively on the same
device, this leaves a redundant device -> host -> device round-trip between
them: the first delegate's output is copied to host and immediately copied
back to the same device for the second delegate.
This adds a third phase to PropagateDevicePass that elides
_h2d_copy(_d2h_copy(x))when the tensor before the D2H already lives on thedevice the H2D copies back to. The device comparison is the correctness guard:
a genuine cross-device move (e.g. cuda:0 -> host -> cuda:1) has differing
devices and is preserved. A D2H that still feeds other (host) consumers keeps
those users and is removed only once it becomes dead. The phase runs only when
enable_non_cpu_memory_planning is set (i.e. when copies were actually
inserted).
This closes the "redundant copies between back-to-back delegates on the same
device" limitation from the device-aware export work.
Reviewed By: Gasoonjia
Differential Revision: D111992997