Skip to content

perf(rules): run custom rules across host processes - #928

Merged
kvlonge merged 3 commits into
mainfrom
perf/rules-off-critical-path
Oct 4, 2026
Merged

kvlonge merged 3 commits into
mainfrom
perf/rules-off-critical-path

Conversation

@kvlonge

@kvlonge kvlonge commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Why

Cold compiles waited on one custom-rule host process: about 16 s of a ~28 s compile on a ~1,400-model project. Custom-rule setup data was computed up to three times, and the speculative lint held the GIL once per body (CHI-441 phase 2).

Changes

  • Split custom rules across host processes: min(available cores, invocations ÷ 64), capped at 8 and cgroup-aware. Results merge into single-host order, with identical cache behaviour.
  • Rules that change module-level state (state across subjects) are detected and re-evaluated in one host, so findings never depend on the host count. Docs explain this under parallel evaluation.
  • On a host failure, a cancel marker stops the other hosts at their next invocation; no signals are sent. The plan then reruns in one host, so the reported error is unchanged.
  • Start custom hosts and built-in rules before SQL-rule preparation; compute custom-rule setup data once.
  • Prepare speculative lint bodies in one native batch.

Verification

  • ~1,400-model project, cold with cache (base → head): 27.6 → 19.8 s wall, 36.7 → 41.9 s CPU, custom rules 16.1 → 8.3 s; output identical. Dense 3k and 10k unchanged (one project-wide rule).
  • Tests: 1-vs-3-host determinism including a stateful duplicate-detector rule (cold, warm, cache on and off), cache reuse across hosts, cancellation latency with no signals sent, cgroup CPU parsing, batched lint output and failure order.
  • One independent review plus a follow-up; make test, make check-ci.

…first

Custom-rule invocations are dealt round-robin by subject across up to one host
process per available core, then merged back into single-host order so
findings, read sets, untracked and uncacheable rules, observed digests, and the
custom-rule cache are identical to one host. Any host failure reruns the whole
plan in one host so the reported error is exactly the single-host error.

Rule evaluation now launches the custom hosts and native built-in rules before
preparing SQL rule inputs, and computes custom rule payloads and implementation
fingerprints once instead of up to three times.
The early SQL lint expanded and prepared each body with its own native call,
handing the GIL back and forth with graph building thousands of times. Bodies
are now expanded first and prepared in one GIL-free native call; a body the
batch cannot prepare is prepared again on its own so failures surface exactly
as before, in file order relative to expansion failures.
Rules that change module-level state on any host are evaluated again in one
host over all of their subjects, replacing their split results, so cross-subject
state such as a duplicate detector reports exactly what one host reports. The
host count now honours cgroup v1 and v2 CPU quotas and is capped at eight.

The first failing host writes a per-run cancellation marker. The other hosts
check it between invocations, outside any Rule's guarded scope, and exit with a
distinct cancelled status, and hosts that start late exit at once; no process is
ever signalled. One invocation that is already running still ends or reaches its
own timeout. One host then reruns the plan to report the single-host error.
@kvlonge
kvlonge enabled auto-merge (squash) October 3, 2026 23:49
@kvlonge
kvlonge merged commit ee6ea4f into main Oct 4, 2026
36 checks passed
@kvlonge
kvlonge deleted the perf/rules-off-critical-path branch October 4, 2026 00:08
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