perf: cache _source_key and make _walk_python_tree iterative - #2765
perf: cache _source_key and make _walk_python_tree iterative#2765EinWenigDaneben wants to merge 1 commit into
Conversation
- Memoize _source_key((source_file, root)) to skip repeated filesystem stat/realpath calls per node/edge/raw_call during extraction. - Replace recursive generator in _walk_python_tree with an iterative pre-order stack walk so large tree-sitter trees no longer re-forward every descendant through the call chain. - Add regression tests locking pre-order identity and memo stability. Measured ~46% faster single-worker extract on a 357-file PHP corpus (2.20s -> 1.18s best-of-3).
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. 1 change(s) tested, no difference found (not proven).
Graphify review — findings
This PR applies two performance-oriented changes in the resolution extractor. It adds a module-level _SOURCE_KEY_CACHE memo to _source_key (keyed by source_file and root) and clears it at the start of each extract() run, and it rewrites _walk_python_tree from a recursive yield from generator into an iterative explicit-stack pre-order DFS. It also adds a new test file (test_hermes_verified_optimizations.py) that checks the iterative walk matches the previous recursive traversal order and that _source_key memoization returns stable results and populates the cache. The changed-symbols list is broad, but the actual diff touches only extract.py, resolution.py, and the new test file.
No blocking issues surfaced. 1 lower-confidence candidate did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1654 functions depend on the 334 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 454 callers, 41 callees - new:
_rebuild_code()— 95 callers, 51 callees - new:
_extract_generic()— 18 callers, 23 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
dispatch_command()— 2 callers, 117 callees - new:
extract_js()— 76 callers, 3 callees - new:
_resolve_js_module_path()— 27 callers, 6 callees - …and 38 more
Verification — 1654 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1514 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify extract.
The verifier did not have enough to check extract, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `cache_root` is annotated `Path | None` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_source\_key.
The verifier did not have enough to check \_source\_key, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set
No difference found (not proven): No behavior difference found in \_walk\_python\_tree (not a proof).
The verifier ran both versions of \_walk\_python\_tree on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: concolic exploration (CrossHair). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
· 46 more finding(s) on lines outside this diff (see the check run).
What
Two extraction-path performance improvements.
Cache
_source_keyfilesystem resolution (graphify/extractors/resolution.py) — memoize on(source_file, root), cleared once perextract()run; skips repeatedstat/realpathsyscalls per node/edge/raw_call.Iterative
_walk_python_tree— replace the recursive generator (yield fromre-forwards every descendant through the call chain, O(depth) per node) with an explicit-stack pre-order walk; each node yielded exactly once. Same node order.Evidence
Single-worker extract on a 357-file PHP corpus, best-of-3:
~46% faster on the measured corpus.
Tests
tests/test_hermes_verified_optimizations.pylocks pre-order identity of the iterative walk +_source_keymemo stability. Rest of the suite: only pre-existing failures (test_skillgen,test_ollama_retry_cap) which also fail on unpatchedv8.