Skip to content

perf(rules): reuse compile front-end work in lint and SQL rules - #884

Merged
kvlonge merged 7 commits into
mainfrom
perf/chi-324-lint-front-end-reuse
Sep 29, 2026
Merged

kvlonge merged 7 commits into
mainfrom
perf/chi-324-lint-front-end-reuse

Conversation

@kvlonge

@kvlonge kvlonge commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Why

On the dense all-rules benchmark, the rules phase repeated front-end work the compile had already done: per-file path resolution and containment checks, character-by-character header scanning, rebuilding the declaration scope index, and a second walk and read of every project file. Once that work got faster, a latent race also made the native rules request start without the custom-rule host and retry in full.

Changes

  • Lint classifies each file path once and skips resolve() when no dynamic-output proofs exist; header scanning jumps between delimiters with a compiled pattern.
  • The early SQL lint thread reuses the compiler's declaration scope index when macro metadata matches (own macro instances kept for thread safety), falling back to a full build otherwise.
  • Compiler SQL rules reuse the early lint thread's project file snapshot when rule codes and project directory match.
  • Custom-host startup is decided from the rules cache state read before evaluation starts.

Verification

  • Dense 5k cold: 38.8 s -> 36.9 s wall, 71.9 -> 67.9 CPU-s; built-in rules 14.1 s -> 9.7 s; warm unchanged.
  • Dense fingerprints unchanged; findings-heavy project (501 errors) and 108 rule fixture projects byte-identical; header scanner fuzzed against the old loop.
  • Race reproduced on main by a new integration test; make test, make check-ci, dense 5k guard under 4 GiB; one independent review.

…racter loops

Compute each file's project-relative role once instead of repeating pathlib containment checks per body, skip resolving paths when no dynamic-output proofs exist, and jump between header delimiters with a compiled pattern. Header spans, body ranges and findings are unchanged.
The background SQL lint still loads its own macro instances, but when their indexed metadata matches the compiler's it reuses the already validated scope index and relationship grants instead of rebuilding them. Any metadata difference falls back to a full private build.
When the early lint matches the selected SQL rules and project directory, the SQL rule pass reuses its full-project file read for rule identities and dynamic-output proofs instead of walking and re-reading every SQL file on the main thread.
…fore evaluation

Native evaluation checked whether the rules cache existed only after building its payloads, while the concurrent SQL rule pass could already have created that directory. When that happened the request omitted the custom host, failed, and was repeated with it. The cache state is now captured before either phase starts.
Pin exact header spans for escaped and unterminated quotes, prove that a rebound declaration scope matches a fresh build while keeping private macro instances, check that cold compiles build the scope once and reuse the early file read, reproduce the custom-host request ordering deterministically, and compare compile-time SQL findings with a standalone rule run on CRLF and macro inputs.
@kvlonge
kvlonge enabled auto-merge (squash) September 29, 2026 10:13
…nt-end-reuse

# Conflicts:
#	tests/unit/src/sqlbuild/compiler/compile/_helpers/_test_types.py
#	tests/unit/src/sqlbuild/compiler/compile/_helpers/helpers.py
@kvlonge
kvlonge merged commit ba67825 into main Sep 29, 2026
29 checks passed
@kvlonge
kvlonge deleted the perf/chi-324-lint-front-end-reuse branch September 29, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant