Skip to content

[PERF] Reduce cold graph extraction work on large Python projects #59

Description

@TristanKruse

[PERF] Reduce cold graph extraction work on large Python projects

Problem

The current 5,000-leaf-module comparison corpus contains 5,005 Python files
and 13,738 import edges. The published end-to-end fresh-process median for
one ArchUnitPython boundary rule was 3.59 s (v1.5.0, commit
09c9d199dec095aaa60be227bfd7b5c2b7ffb107, Python 3.13.4, Windows 11).

Exploratory timing of one direct rule.check() found graph extraction taking
roughly 1.8–2.6 s, depending on machine load. Within that phase,
_extract_located_imports() accounted for about 1.2–1.7 s over 5,005 files,
and import resolution about 0.37–0.51 s over 13,738 imports. These components
are cumulative instrumentation measurements, not independent benchmark bars.

The source suggests two specific sources of avoidable work:

  • Each parsed file is walked separately to find TYPE_CHECKING blocks,
    conditional import ranges, and actual imports/calls.
  • Absolute imports are resolved through repeated filesystem existence checks,
    even though the scan already has the set of project Python files.

Proposed investigation and implementation

  1. Add phase timings and peak memory to the regression benchmark in [Test] Benchmark for ArchUnitPython #55.
  2. Try a single AST visitor that records contextual import kinds and imports
    in one traversal. Compare it with current behavior on nested conditions.
  3. Build a module/file lookup from the discovered project files and use it
    for internal absolute-import resolution; retain current semantics for
    package __init__.py, relative imports, parent roots, and external modules.
  4. Profile again before considering parallel parsing or a persistent disk
    cache. A disk cache needs explicit invalidation semantics and a separate
    correctness test matrix.

Acceptance criteria

  • Existing tests and seeded direct-boundary/cycle correctness gates pass.
  • Tests cover relative and absolute imports, TYPE_CHECKING, optional imports,
    literal dynamic imports, ignore directives, excluded paths, and malformed
    Python files.
  • Report before/after fresh-process p50/p95 at 100/1,000/5,000 modules,
    extraction phase time, and peak memory. Preserve zero runtime dependencies.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions