Skip to content

[perf-scan] 2026-09-14 -- performance opportunities found #2974

Description

@github-actions

Performance Scan - 2026-09-14

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

Findings

[B] Linear scan inside a loop -- src/apm_cli/commands/uninstall/engine.py:189-260

  • Current: O(n*m) -- _stage_shared_local_survivors loops over
    packages_to_remove (n) and calls _surviving_local_refs_at_install_path
    (line 196), which itself linearly scans all of surviving_dependencies (m)
    on every call. The same helper is also called again per-package inside
    _dry_run_uninstall (line 756), doubling the cost on --dry-run.
  • Proposed: O(n+m) -- pre-index surviving_dependencies once into a
    dict[install_path, list[DependencyReference]] before either loop, then
    do an O(1) dict lookup per package instead of an O(m) scan.
  • Fix: Build a install_path -> [local survivors] dict once outside both
    loops in engine.py and replace the repeated calls to
    _surviving_local_refs_at_install_path with a lookup against that dict.

[E] Heavy top-level imports on CLI command modules -- src/apm_cli/commands/install.py:1-53

  • Current: apm.commands.install is imported eagerly by
    src/apm_cli/cli.py:38 for every CLI invocation, and it in turn performs
    53 top-level imports (agent_plugins, copilot_plugins, install.argv,
    install.artifactory_resolver, install.dry_run_plan, install.errors,
    install.gitlab_resolver, install.helpers.ref_reuse,
    install.manifest_helpers, install.finalization, install.helpers.security_scan,
    etc.) that are only exercised when the user actually runs apm install.
    Every other subcommand (e.g. apm view, apm config) pays this import
    cost at process startup.
  • Proposed: defer the install-only heavy imports (artifactory_resolver,
    gitlab_resolver, dry_run_plan, manifest_helpers, security_scan) to inside
    the install() command function body, keeping only what's needed for
    Click registration (the install callable itself) at module import time.
  • Fix: Move the imports in src/apm_cli/commands/install.py lines 14-51
    that are only referenced inside the install/helper function bodies to
    local imports inside those functions, following the existing pattern
    already used for close_install_contexts deferral elsewhere in the file.

[C] Unconditional directory walk fallback -- src/apm_cli/install/services.py:863-880

  • Current: O(n) unconditional -- when pack_files is empty (older bundle
    without bundle_files metadata), the code falls back to
    bundle_dir.rglob("*") and computes a full sha256 hash of every file in
    the bundle on every deploy for that bundle, with no caching between
    target loops in the same install run.
  • Proposed: this fallback is correctly gated behind if not pack_files:
    already (fast-path skip when bundle metadata is present), so this is a
    low-priority, borderline finding -- it only fires for legacy bundles
    lacking bundle_files, not on every install. Noting for awareness only;
    no action required unless legacy-bundle installs become a hot path.

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)

Generated by Daily Performance Scanner · copilot · auto · 105.2 AIC · ⌖ 6.75 AIC · ⊞ 10.1K ·

  • expires on Sep 21, 2026, 1:42 AM UTC

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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