[perf-scan] 2026-09-17 -- performance opportunities found
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.9k
- Forks
- 365
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 132
Description
Performance Scan - 2026-09-17
Automated scan of src/apm_cli/ for algorithmic performance anti-patterns.
2 finding(s) identified.
Findings
[A] Quadratic loop nesting -- src/apm_cli/commands/uninstall/engine.py:189-230
- Current: O(P*S) where P = packages_to_remove and S = surviving_dependencies.
_stage_shared_local_survivorsiteratespackages_to_remove(line 189) and
calls_surviving_local_refs_at_install_pathfor each package, which itself
scans the fullsurviving_dependencieslist (engine.py:85-104) and
re-parses every entry with_parse_dependency_entry(...).get_install_path(...).
For an uninstall of many packages against a large surviving-dependency set
this becomes quadratic re-parsing/re-resolving of the same install paths. - Proposed: O(P+S). Build a
dict[Path, list[DependencyReference]]once by
parsingsurviving_dependenciesand grouping byget_install_path()
before thepackages_to_removeloop, then do an O(1) dict lookup per
removed package instead of re-scanning and re-parsing the survivor list
each time. - Fix: Pre-index
surviving_dependenciesinto a{install_path: [survivor_refs]}
map once (parsing each survivor exactly once), then replace the call to
_surviving_local_refs_at_install_path(package, surviving_dependencies, ...)
with a dict lookup keyed by the removed package's own install path.
[C] Unconditional expensive operation recomputed per file -- src/apm_cli/install/manifest_reconcile.py:308-331
- Current: O(F*T) where F = deployed file paths and T = active+declared+known
targets.reconcile_deployed_block's inner_target_for(path)closure
(line 308) is invoked once per path via_locator(path)(called at lines
327, 343, 353, 364), and on every invocation it re-iterates the full
targets+declared_targets+scoped_known_targetslist and calls
install_governance([profile])fresh for each profile (line 319) --
recomputing the same per-target prefix/scheme sets for every single
deployed file in the block. - Proposed: O(F+T). Compute the per-target
(prefixes, schemes)governance
once per unique target name before the file loop (adict[str, tuple[set,set]]
keyed byprofile.name), then have_target_fordo O(1) dict lookups
against that pre-built table instead of recomputinginstall_governance
per path. - Fix: Hoist a
target_governance = {p.name: install_governance([p]) for p in ordered}
dict above the_target_forclosure (built once perreconcile_deployed_block
call) and have_target_foriterate that pre-computed table instead of
callinginstall_governance([profile])inside the per-path loop.
Scan coverage
- src/apm_cli/ (484 files scanned)
- Patterns checked: A (quadratic loops), B (linear scan in loop),
C (unconditional expensive ops), D (redundant config parsing),
E (heavy top-level imports), F (sequential independent I/O)
Notes: Pattern E (heavy top-level imports) is already well-mitigated -- the
CLI's _LazyCommand mechanism in cli.py defers imports for install, uninstall,
pack, marketplace, prune, audit, and update to first dispatch. Pattern F
(sequential I/O) is already parallelized in registry/operations.py via
bounded ThreadPoolExecutor for MCP server checks/validation. No confirmed
findings for patterns B or D beyond noise (isolated dict/set membership
checks, not per-iteration linear scans).
Generated by Daily Performance Scanner · copilot · auto · 197.4 AIC · ⌖ 4.46 AIC · ⊞ 10.1K · ◷
- expires on Sep 24, 2026, 1:41 AM UTC
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with _stage_shared_local_survivors in src/apm_cli/commands/uninstall/engine.py and reconcile_deployed_block in src/apm_cli/install/manifest_reconcile.py, tracing their current per-item scans and governance calculations. Verify that the optimization preserves existing uninstall and reconciliation behavior while removing repeated survivor parsing and per-file target governance work; the issue names no specific tests, so inspect nearby coverage before running it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli, performance
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100