⚡️ Speed up method NumericalUsageChecker.visit_Attribute by 228% in PR #1051 (detect-numerical-code)#1052
Closed
codeflash-ai[bot] wants to merge 1 commit into
Closed
Conversation
The optimized code achieves a **227% speedup** (from 1.12ms to 341μs) through two key optimizations: ## 1. Recursive to Iterative Conversion in `_get_root_name` (~46% of original time saved) The original implementation used recursion to traverse attribute chains like `np.linalg.norm`, making a new function call for each level. The line profiler shows `return self._get_root_name(node.value)` consumed 46.9% of the function's time with 725 recursive calls. The optimized version replaces recursion with a `while True` loop that iteratively descends through `Attribute` nodes by reassigning `node = node.value`. This eliminates Python's function call overhead (stack frame creation, argument passing, return handling). The performance impact is visible: the iterative version completes in 1.65ms vs 2.07ms for the original `_get_root_name`. ## 2. Conditional `generic_visit` Call (~47% of visit_Attribute time saved) The original code unconditionally called `self.generic_visit(node)` for every non-matching attribute (509 calls taking 46.9% of `visit_Attribute` time). However, `generic_visit` recursively traverses child nodes—unnecessary work when `_get_root_name` returns a valid name (the attribute chain already led to a `Name` node with no further children to visit). The optimized version only calls `generic_visit(node)` when `root_name is None`, which occurs for non-standard AST node types (like `Call`, `Subscript`, `BinOp`). This reduces `generic_visit` calls from 509 to just 5 in the profiled run, cutting this operation's contribution from 46.9% to 3.1% of total time. ## Test Case Performance Patterns The optimization is most effective for: - **Deeply nested attributes**: `test_large_scale_deeply_nested_chain` shows 172% speedup (28.3μs → 10.4μs) as recursion elimination scales with chain depth - **Many non-matching attributes**: `test_large_scale_library_not_in_large_set` shows 335% speedup by avoiding unnecessary `generic_visit` traversals - **Sequential visits**: `test_large_scale_sequential_visits` shows 329% speedup (379μs → 88.5μs) for 200 visits, demonstrating consistent per-call improvement The optimization has minimal impact on edge cases with non-Name/non-Attribute root nodes (like `Subscript`, `BinOp`) where `generic_visit` must still be called, but these are rare in typical AST traversals. ## Impact Assessment These optimizations are particularly valuable when `NumericalUsageChecker` is used in hot paths analyzing large codebases with many attribute accesses, as the per-call overhead reduction compounds across thousands of AST nodes.
Contributor
Author
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
⚡️ This pull request contains optimizations for PR #1051
If you approve this dependent PR, these changes will be merged into the original PR branch
detect-numerical-code.📄 228% (2.28x) speedup for
NumericalUsageChecker.visit_Attributeincodeflash/code_utils/code_extractor.py⏱️ Runtime :
1.12 milliseconds→341 microseconds(best of250runs)📝 Explanation and details
The optimized code achieves a 227% speedup (from 1.12ms to 341μs) through two key optimizations:
1. Recursive to Iterative Conversion in
_get_root_name(~46% of original time saved)The original implementation used recursion to traverse attribute chains like
np.linalg.norm, making a new function call for each level. The line profiler showsreturn self._get_root_name(node.value)consumed 46.9% of the function's time with 725 recursive calls.The optimized version replaces recursion with a
while Trueloop that iteratively descends throughAttributenodes by reassigningnode = node.value. This eliminates Python's function call overhead (stack frame creation, argument passing, return handling). The performance impact is visible: the iterative version completes in 1.65ms vs 2.07ms for the original_get_root_name.2. Conditional
generic_visitCall (~47% of visit_Attribute time saved)The original code unconditionally called
self.generic_visit(node)for every non-matching attribute (509 calls taking 46.9% ofvisit_Attributetime). However,generic_visitrecursively traverses child nodes—unnecessary work when_get_root_namereturns a valid name (the attribute chain already led to aNamenode with no further children to visit).The optimized version only calls
generic_visit(node)whenroot_name is None, which occurs for non-standard AST node types (likeCall,Subscript,BinOp). This reducesgeneric_visitcalls from 509 to just 5 in the profiled run, cutting this operation's contribution from 46.9% to 3.1% of total time.Test Case Performance Patterns
The optimization is most effective for:
test_large_scale_deeply_nested_chainshows 172% speedup (28.3μs → 10.4μs) as recursion elimination scales with chain depthtest_large_scale_library_not_in_large_setshows 335% speedup by avoiding unnecessarygeneric_visittraversalstest_large_scale_sequential_visitsshows 329% speedup (379μs → 88.5μs) for 200 visits, demonstrating consistent per-call improvementThe optimization has minimal impact on edge cases with non-Name/non-Attribute root nodes (like
Subscript,BinOp) wheregeneric_visitmust still be called, but these are rare in typical AST traversals.Impact Assessment
These optimizations are particularly valuable when
NumericalUsageCheckeris used in hot paths analyzing large codebases with many attribute accesses, as the per-call overhead reduction compounds across thousands of AST nodes.✅ Correctness verification report:
🌀 Click to see Generated Regression Tests
To edit these changes
git checkout codeflash/optimize-pr1051-2026-01-14T02.21.37and push.