[executorch][arm] Speed up lowering: cache constant names, fix quadratic permute chain collection, dedup producer queue, defer cleanup, and drop redundant recompiles - #21696
Conversation
…osaOps Summary: RemovePermutesAroundElementwiseTosaOps._is_constant called is_param_node() for every node reached during recursive visit() walk. Each is_param_node rebuilds immutable dict over full input_specs via uncached graph_signature properties. This made pass O(nodes * inputs). Precompute union of param/buffer/lifted-constant placeholder names once in __init__ and use O(1) set membership. Semantics unchanged. Differential Revision: D114224782
Summary: Speed up permute propagation cleanup. ARM lowering spends significant time in permute propagation. Reduce avoidable repeated work while keeping same optimizations: - Canonicalize view/permute chain collection now uses deque + membership set instead of list pop(0) and remove(), avoiding quadratic bookkeeping. - FuseDuplicateUsersPass deduplicates pending producer revisits while preserving same revisit behavior after fusions. - PropagateViewCopyPermutePass still retraces after each moved transform for metadata safety, but defers horizontal/vertical cleanup until full scan finds no more direct propagation moves. Preserves fixed-point behavior while avoiding expensive cleanup after every single moved transform. Behavior-preserving speedup, all existing pass tests pass. Differential Revision: D114224762
Summary: Skip redundant recompile in identical-input transform fusion. Remove redundant GraphModule.recompile() immediately before super().call() in FuseIdenticalInputTransformsPass. Pass already eliminates dead code and lints before handing to ARM framework for retracing. Recompiling Python GraphModule at that point is unnecessary because ExportPass call reconstructs/interprets graph rather than relying on just-compiled code object. Behavior-preserving speedup. Differential Revision: D114790128
Summary: Drop redundant recompile() before ARM pass retracing. Remove redundant GraphModule.recompile() calls immediately before super().call(graph_module) in CanonicalizeViewCopyPermutePass and FuseDuplicateUsersPass. The following ExportPass retrace/interpreter does not consume compiled Python code object, so recompile adds wall time without changing graph. Keep graph.lint() in modified paths for invariant checking. Behavior-preserving lowering speedup. Differential Revision: D114790155
Summary: Remove redundant GraphModule.recompile() at end of PropagateViewCopyPermutePass.call(). When pass modifies graph it already calls _retrace(), which eliminates dead code, lints, and runs ARM ExportPass retracing to return rebuilt graph module. Immediately following recompile() recompiles Python code not needed before pass manager continues, adding wall time. Keep _retrace() and drop extra compile step. Differential Revision: D114790177
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21696
Note: Links to docs will display an error until the docs builds have been completed. ❌ 2 New Failures, 1 Unrelated FailureAs of commit 1c91383 with merge base 730b77a ( NEW FAILURES - The following jobs have failed:
FLAKY - The following job failed but was likely due to flakiness present on trunk:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
@apullin has exported this pull request. If you are a Meta employee, you can view the originating Diff in D114790177. |
This PR needs a
|
Summary:
This is a stack of 5 commits that speed up various parts of the model lowering process. I have been testing with ~1M param models, and lowering time has been 60+ minutes. This is an unfortunate reality from being implemented in Python, and ET will always struggle with networks of even moderate size BUT there is still plenty of performance left on the table.
The summary for each commit/diff are as follow:
D114790177:
Remove redundant
GraphModule.recompile()at end ofPropagateViewCopyPermutePass.call().When pass modifies graph it already calls
_retrace(), which eliminates dead code, lints, and runs ARM ExportPass retracing to return rebuilt graph module. Immediately followingrecompile()recompiles Python code not needed before pass manager continues, adding wall time.Keep
_retrace()and drop extra compile step.D114790155:
Drop redundant
recompile()before ARM pass retracing.Remove redundant
GraphModule.recompile()calls immediately beforesuper().call(graph_module)inCanonicalizeViewCopyPermutePassandFuseDuplicateUsersPass. The following ExportPass retrace/interpreter does not consume compiled Python code object, so recompile adds wall time without changing graph.Keep
graph.lint()in modified paths for invariant checking. Behavior-preserving lowering speedup.D114790128:
Skip redundant recompile in identical-input transform fusion.
Remove redundant
GraphModule.recompile()immediately beforesuper().call()in FuseIdenticalInputTransformsPass. Pass already eliminates dead code and lints before handing to ARM framework for retracing. Recompiling Python GraphModule at that point is unnecessary because ExportPass call reconstructs/interprets graph rather than relying on just-compiled code object. Behavior-preserving speedup.D114224762:
Speed up permute propagation cleanup.
ARM lowering spends significant time in permute propagation. Reduce avoidable repeated work while keeping same optimizations:
Canonicalize view/permute chain collection now uses deque + membership set instead of list
pop(0)andremove(), avoiding quadratic bookkeeping.FuseDuplicateUsersPassdeduplicates pending producer revisits while preserving same revisit behavior after fusions.PropagateViewCopyPermutePassstill retraces after each moved transform for metadata safety, but defers horizontal/vertical cleanup until full scan finds no more direct propagation moves. Preserves fixed-point behavior while avoiding expensive cleanup after every single moved transform.Behavior-preserving speedup, all existing pass tests pass.
D114224782:
RemovePermutesAroundElementwiseTosaOps._is_constantcalledis_param_node()for every node reached during recursivevisit()walk. Eachis_param_noderebuilds immutable dict over full input_specs via uncached graph_signature properties. This made pass O(nodes * inputs). Precompute union of param/buffer/lifted-constant placeholder names once in init and use O(1) set membership. Semantics unchanged.Differential Revision: D114224782 D114224762 D114790128 D114790155 D114790177
cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani