Skip to content

[perf-scan] 2026-08-14 -- performance opportunities found #2573

Description

@github-actions

Performance Scan - 2026-08-14

Automated scan of src/apm_cli/ for algorithmic performance anti-patterns.
2 finding(s) identified.

Findings

[A] Cumulative Re-Sort at Every BFS Level -- src/apm_cli/deps/apm_resolver.py:728-734

  • Current: O(D x N log N) -- _select_dependency_winners(winner_candidates) is called at every BFS depth level with the full accumulated list of ALL previously seen nodes. winner_candidates grows by one level per iteration, but the sort always starts from scratch, touching every node seen so far.
  • Proposed: O(N log N) total -- maintain winner_ids as an incrementally-updated dict; on each new node, apply the same depth-first, get_id() tie-break rule without re-sorting the entire history.
  • Fix: Replace the per-level _select_dependency_winners(winner_candidates) call with an incremental update: winner_ids.setdefault(node.dependency_ref.get_unique_key(), node.get_id()) once per new node (depth ordering is already guaranteed by BFS level batching), and remove the winner_candidates accumulator entirely.

[A] O(n) Linear Child Membership Check in BFS Resolution Loop -- src/apm_cli/deps/apm_resolver.py:698-700,819-820

  • Current: O(k) per call -- all(child is not X for child in parent_node.children) scans the entire children list to verify a node is not already present before appending. Called at lines 698-700 and 819-820, once per dependency edge resolved in the BFS loop.
  • Proposed: O(1) per call -- use a parallel set of child node IDs on DependencyNode.
  • Fix: Add a children_set: set[str] field to DependencyNode (populated alongside children.append); replace both all(child is not X for child in node.children) guards with X.get_id() not in parent_node.children_set.

Scan coverage

  • src/apm_cli/ (430 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)

Generated by Daily Performance Scanner · 110.6 AIC · ⌖ 6.18 AIC · ⊞ 7.3K ·

  • expires on Aug 21, 2026, 1:45 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions