Skip to content

perf(compile): close the fresh compile gap with ordered native scheduling and mimalloc - #889

Merged
kvlonge merged 6 commits into
mainfrom
perf/chi-411-native-validation
Sep 30, 2026
Merged

kvlonge merged 6 commits into
mainfrom
perf/chi-411-native-validation

Conversation

@kvlonge

@kvlonge kvlonge commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Why

Fresh 3000-model --no-cache compiles were 1.175x wall / 1.16x CPU of 0.119.1. Native query analysis runs in dependency waves whose wall time was set by one or two huge queries that started late, about 40% of native CPU was the system allocator, and SQL-test comparison rendering re-parsed the same model SQL for every test.

Changes

  • Native analysis waves take queries from a shared queue, largest SQL first; results keep request order.
  • mimalloc (v3, local-dynamic TLS) as the native extension's allocator; no memory crosses the Python boundary.
  • SQL-test comparison rendering reuses a parse once the same SQL repeats, capped at 1 MiB of SQL text.
  • Fresh same-runner compile ratio limit back to 1.10.
  • New build-only wheels job builds and smoke-imports every published wheel platform on PRs that change native inputs; it feeds Verify.

Verification

  • Fresh 3000 --no-cache vs 0.119.1: 1.042x wall, 1.010x CPU (was 1.175x / 1.16x); peak memory 829 -> 682 MB. Dense 3000 20.75 -> 19.78 s.
  • Fingerprints and saved JSON byte-identical (fresh, dense 1k/3k; no-cache, cold, warm); native SQL-test planning output identical.
  • Fresh-process, dense, cache and diagnostic guards under 4 GiB; Rust tests, clippy and fmt (1.98); make test, make check-ci; one independent review.

Hand out each native analysis batch through a shared queue ordered by SQL size, so the widest queries start first instead of becoming a late critical path. Results keep request order. Fresh 3000 native analysis wall falls from about 2.24 s to 1.91 s with identical output.
Native analysis spends about 40% of its time in the system allocator building and dropping syntax trees. mimalloc (local-dynamic TLS for the dlopen-loaded extension) cuts fresh 3000 native analysis from about 6.4 to 4.8 CPU-s and 1.9 to 1.4 s wall with identical output. Fresh 3000 peak memory falls from about 830 to 690 MB; dense 3000 CPU falls about 7% at similar peak memory.
Tests in one project render the same model SQL many times while lifting its CTEs into the comparison query; fresh 3000 splits about 1,150 statements from only 50 distinct SQL strings. Keep a parse of SQL once it repeats within a render batch, bounded to 1 MiB of SQL text, and clone it for each later use; per-test CTE renaming is unchanged. Unrepeated SQL is never retained, so dense projects keep their peak memory. Fresh 3000 native planning and rendering falls from about 455 to 380 ms with identical artifacts.
Fresh 3000 --no-cache is back within 1.10x of 0.119.1 on the same machine (medians of 3 interleaved runs: 8.22 s vs 7.86 s wall, 12.56 vs 12.54 CPU-s), so the temporary 1.30 limit is no longer needed.
…puts

Build the same Linux, macOS and Windows wheel matrix as publish.yml, without uploading, whenever crates, Cargo manifests, pyproject.toml or the verify workflow change, and smoke-import sqlbuild._native from each built wheel. The aggregate Verify job treats the job like the other path-selected suites.
@kvlonge
kvlonge enabled auto-merge (squash) September 30, 2026 16:31
@kvlonge
kvlonge merged commit eb9af35 into main Sep 30, 2026
33 checks passed
@kvlonge
kvlonge deleted the perf/chi-411-native-validation branch September 30, 2026 17:35
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