Skip to content

[perf-scan] 2026-08-23 -- performance opportunities found #2668

Description

@github-actions

Performance Scan - 2026-08-23

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

Findings

[B] Linear scan inside nested loop -- security/executables.py:267-288 and 747-755

  • Current: O(K * E * C * G) -- _map_grants iterates all entries of each grant_map
    dict (O(G)) including calling _strip_version(stored_key) per entry. Called C=4-6
    times per resolve_exec_decision, which is itself called inside a nested loop:
    for key in candidate_keys: for exec_type in ALL_EXEC_TYPES (lines 747-755) and
    a second nested loop at lines 779-782. K=candidate_keys, E=exec_types (~4),
    G=grant_map size.
  • Proposed: O(K * E) after O(G) pre-build -- build a
    {stripped_key: {exec_type: bool}} index from each grant_map (user_allow,
    user_deny, project_allow, project_deny) once before the outer loop.
  • Fix: In _map_grants, add an optional pre-built normalized-key index parameter;
    before the outer for key in candidate_keys loop, call a helper that produces
    dict[str, dict[str, bool]] keyed by _strip_version(stored_key) for each
    grant_map, then replace the linear scan with an O(1) dict lookup.

[B] O(n*m) prefix scan on deployed files -- bundle/lockfile_enrichment.py:151

  • Current: O(n * m) -- [f for f in deployed_files if any(f.startswith(p) for p in prefixes)] iterates all deployed files (n) and for each file checks all
    target prefixes (m) until a match is found. Called during apm pack and bundle
    export operations.
  • Proposed: O(n * log(m)) or amortised O(n) -- sort prefixes once and use
    bisect to find the longest candidate prefix per file, or group files by
    common prefix using a trie-like dict keyed on the first path segment.
  • Fix: Sort prefixes by length descending once before the comprehension and
    break early; for large deployments, build a {first_segment: [prefixes]} dict
    to skip non-matching prefixes in O(1) per file. Low-priority: m is typically
    10-20 entries, so the fix matters mainly for deployments with hundreds of files.

Scan coverage

  • src/apm_cli/ (445 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 · 141.7 AIC · ⌖ 8.78 AIC · ⊞ 7.3K ·

  • expires on Aug 30, 2026, 1:42 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/automationAutomation script, workflow, gh-aw, dependabot config.type/performanceLatency, throughput, memory, install time.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions