Skip to content

perf(codegen): array families in one SCC pass; Fx hashing for the analysis maps - #12791

Merged
proggeramlug merged 1 commit into
mainfrom
cfast-array-families
Oct 18, 2026
Merged

proggeramlug merged 1 commit into
mainfrom
cfast-array-families

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

array_families::collect propagated each property write separately through the module's flow graph: a work-list per write into HashMap<Node, BTreeSet<usize>>, with nodes holding owned field names and SipHash on every step. On tsc it took ~8 s per call, and codegen calls it twice per module (births pre-pass + compile). In a frame-pointer profile of a tsc compile it held 71% of the SipHash samples of the serial phases.

Change (no behavior change)

  • Flow nodes are interned to u32 (field names borrowed from the HIR); edges live in one array.
  • Both propagations (call targets, then write keys) are one pass over the strongly connected components in topological order: a component's sorted item set is complete once every component reaching it is done, then merges into each successor component once. Only births' and callees' sets are kept.
  • Same facts, same key order (first write first), same descriptor names.
  • The Fx hasher moves from perry_wpfacts::pts to perry_hir::fx (wpfacts re-exports it); layout_families::late uses it (its next-largest SipHash user, lookups only).

Verification (qb8, base = c081ed7)

  • Old and new algorithms compared per module (temporary check, removed): tscwork 6/6, zodwork 4/4, fastify_inject 572/572, effect 342/342 modules identical (layouts + birth assignments).
  • Linked binaries byte-identical base vs head on all four (sha256); base compiled twice is identical too, so no hash iteration order reaches output. Run parity unchanged.
  • Unit tests: propagation vs a per-item search on random cyclic graphs; SCC numbering; merge.
  • pmcheck: build, zod/tsc smoke, -p perry-codegen --lib layout (75 tests).

tsc compile phases (tscwork): births pre-pass 9.8–11.9 s → 2.4 s; class dispatch and representation analysis 11.3–13.8 s → 3.4 s. Interleaved n=3 instructions:u / task-clock in a follow-up comment.

Found while doing this (fixed in a follow-up PR): the address-keyed BIRTH_LAYOUTS table misses every birth inside a closure, because collectors/closures.rs lowers closure bodies from deep clones — on tsc 606 births are assigned and 0 hit. The follow-up moves the layout onto the HIR birth and deletes the table.

…lysis maps

array_families::collect propagated each property write on its own through
the whole-module flow graph (a work-list per write into
HashMap<Node, BTreeSet>, nodes holding owned field names, SipHash). On tsc
that was ~8 s per call; codegen calls it twice per module (the births
pre-pass and the compile), and it held 71% of the SipHash samples of the
serial phases.

The flow graph now interns its nodes as u32 (field names borrowed from the
HIR) and keeps its edges in one array. Each propagation (call targets, then
write keys) is one pass over the strongly connected components in
topological order: a component's sorted item set is complete once every
component reaching it is done, and it merges into each successor component
once. Only the births' and callees' sets are kept. Same facts, same key
order (first write first), same descriptor names: on tsc, zod, fastify and
effect every module's layouts and births matched the previous algorithm, and
the linked binaries are byte-identical.

The Fx hasher moves from perry_wpfacts::pts to perry_hir::fx (wpfacts
re-exports it) so codegen can use it; layout_families::late's maps use it.
Their iteration order never reaches output: the binaries are identical, and
a base compiled twice is identical to itself.

tsc (tscwork, qb8): births pre-pass 9.8-11.9 s -> 2.4 s, class dispatch and
representation analysis 11.3-13.8 s -> 3.4 s.
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2cc2b460-dfbb-472d-9a68-1a8464ee1666
📥 Commits

Reviewing files that changed from the base of the PR and between 785bc1d and 091ecec.

📒 Files selected for processing: 6
  • crates/perry-codegen/src/layout_desc/array_families.rs
  • crates/perry-codegen/src/layout_desc/array_families_tests.rs
  • crates/perry-codegen/src/layout_families/late.rs
  • crates/perry-hir/src/fx.rs
  • crates/perry-hir/src/lib.rs
  • crates/perry-wpfacts/src/pts.rs
+-------------------------------------------------------------+
| Tabs vs spaces? You somehow chose violence *and* confusion. |
+-------------------------------------------------------------+
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

tsc compile (tscwork), qb8, base c081ed7 vs head, interleaved n=3, taskset 0-13, host load 17-49 (shared host; instructions:u is the primary number):

base (median) head (median) Δ
compile instructions:u 5,187.99 G 5,136.97 G −51.0 G (−0.98%)
births pre-pass 10.8 s 1.8 s −9.0 s
class dispatch + representation analysis 12.8 s 3.6 s −9.2 s
lowering total (module) 90.2 s 81.9 s −8.3 s
compile wall 472.1 s 445.9 s −26 s (noisy)
peak RSS 9.09 GB 9.08 GB flat
output binary sha256 55f2037bc147 55f2037bc147 identical

The remaining serial lowering is the closure-body stage (~55 s), the next item in the compile-speed plan.

@proggeramlug
proggeramlug marked this pull request as ready for review October 18, 2026 10:09
@proggeramlug
proggeramlug merged commit 5518d4a into main Oct 18, 2026
105 of 131 checks passed
@proggeramlug
proggeramlug deleted the cfast-array-families branch October 18, 2026 10:10
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