Skip to content

perf: targeted performance improvements for E2E pipeline#2132

Draft
KRRT7 wants to merge 12 commits intomainfrom
cf-perf-improvements
Draft

perf: targeted performance improvements for E2E pipeline#2132
KRRT7 wants to merge 12 commits intomainfrom
cf-perf-improvements

Conversation

@KRRT7
Copy link
Copy Markdown
Collaborator

@KRRT7 KRRT7 commented May 7, 2026

Targeted performance improvements for the E2E optimization pipeline hot path, plus bug fixes discovered during profiling.

PR stack (deep linear — merge bottom-up)

# PR Branch Description
1 #2145 fix/mypy-strict-errors fix: resolve mypy strict errors in models.py and code_utils.py
2 #2144 fix/test-files-silent-dedup fix: silently skip duplicate TestFiles.add() instead of raising
3 #2138 fix/windows-junitxml-path fix: Windows junitxml path handling
4 #2141 fix/subprocess-xml-errors fix: surface subprocess errors when pytest XML is missing
5 #2134 perf/discovery-prefilter perf: prefilter files by path before read_text()
6 #2135 perf/discovery-ast-cache perf: cache file reads and AST parses per discovery run
7 #2136 perf/discovery-js-read perf: read JS/TS files once during discovery export checks
8 #2137 cf-2132-skip-callers-json-decode perf: skip unused callers JSON decode in ProfileStats
9 #2143 perf/misc-hot-path perf: misc hot-path optimizations (lru_cache, copy, set dedup, .get())
10 #2132 cf-perf-improvements this umbrella (accumulates all above)

Previously merged (already on main): #2128, #2129, #2130, #2131, #2140, #2142

Design decisions

  • No behavioral changes in perf PRs: every optimization preserves identical semantics
  • Bug fixes first: fixes land before perf changes so they propagate through the stack
  • Deep linear stack: each PR targets the branch below it; when bottom merges to main, GitHub auto-retargets the next one
  • Discovery-scoped cache: discovery_cache() context manager ensures no cross-run leakage
  • Dead code removal: _find_all_functions_via_language_support() removed (never called, had pre-existing type error)

Test plan

  • uv run prek passes on all 9 layers individually
  • Full unit test suite passes (4206 tests, 0 regressions)
  • Java tracer/profiler e2e tests pass
  • JS/TS tests pass
  • Cumulative benchmark (TBD)

@KRRT7 KRRT7 marked this pull request as draft May 7, 2026 03:42
Copy link
Copy Markdown
Contributor

@aseembits93 aseembits93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ci failing

KRRT7 added 8 commits May 7, 2026 17:46
Moves path-based checks (test file detection, ignore paths, submodule
paths, site-packages, outside module-root) to run BEFORE read_text() is
called in get_all_files_and_functions() and get_functions_within_lines().
This avoids unnecessary file I/O for files that would be discarded by
filter_functions() anyway.

Also fixes pre-existing mypy error in _find_all_functions_via_language_support
where discover_functions was called with wrong argument order.

Signature changes (backward-compatible, all new params are optional):
- get_all_files_and_functions: added tests_root, module_root params
- get_functions_within_lines: added tests_root, ignore_paths, module_root
- get_functions_within_git_diff: added tests_root, ignore_paths, module_root
Introduces a discovery-scoped cache (`discovery_cache()` context
manager) that ensures each file is read from disk at most once and
parsed into an AST at most once within a single discovery run.

Key changes:
- `read_file_cached()`: returns cached file content when
  `discovery_cache()` is active, falls back to normal read otherwise
- `parse_ast_cached()`: returns cached `ast.Module` when active
- `get_functions_to_optimize()`: wraps its body with `discovery_cache()`
- `find_all_functions_in_file()`: uses `read_file_cached`
- `inspect_top_level_functions_or_methods()`: uses `parse_ast_cached`
- `get_all_replay_test_functions()`: uses `parse_ast_cached`
- JS/TS export helpers: use `read_file_cached`
- Removed dead code: `_find_all_functions_via_language_support()` (never
  called, had a type error passing Path as source str)

Signature changes: None. All public function signatures are unchanged.
The cache is transparent -- when not inside `discovery_cache()`, all
functions behave identically to before (direct reads/parses).
The _is_js_ts_function_exported and _is_js_ts_function_exists_but_not_exported
helpers each read the file from disk independently, causing up to 2 extra reads
per file during get_functions_to_optimize. Add an optional `source` parameter
to both functions so callers can pass pre-read content. The main call site now
reads the file once and passes it to both helpers.

Also fixes pre-existing mypy error in _find_all_functions_via_language_support
where discover_functions was called with wrong argument order.

Signatures changed:
- _is_js_ts_function_exported(file_path, function_name, source=None)
- _is_js_ts_function_exists_but_not_exported(file_path, function_name, source=None)
The --file path was calling file.read_text() directly even though
find_all_functions_in_file() already primed the discovery cache.
Now uses read_file_cached() to hit the cache with zero disk I/O.
The callers BLOB column was fetched and JSON-decoded for every row
during FunctionRanker initialization, but the resulting data was
never accessed — FunctionRanker.load_function_stats() discards it
as `_callers`. This eliminates O(n) JSON parsing at ranking startup.

Also fixes all pre-existing mypy errors in this file by declaring
pstats.Stats attributes that the type stubs don't expose.
KRRT7 added 2 commits May 7, 2026 17:46
…ite.getsitepackages

The lru_cache on _get_site_packages_paths() retained stale results
across tests, causing 4 failures when monkeypatch replaced the
underlying site.getsitepackages function.
The `_extract_names_from_annotation` method accessed
`self.definitions[self.current_top_level_name]` without verifying
that `current_top_level_name` exists in the definitions dict. When
visiting methods inside built-in types (e.g., `str.removeprefix`),
the dotted name was set as `current_top_level_name` but never added
to `definitions`, causing a KeyError on CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants