Skip to content

perf(ml): P2-1 lui_flex clean-child fast lanes - #230

Merged
tiensonqin merged 5 commits into
feat/ml-backendfrom
perf/ml-p2-1-flex
Oct 13, 2026
Merged

tiensonqin merged 5 commits into
feat/ml-backendfrom
perf/ml-p2-1-flex

Conversation

@tiensonqin

Copy link
Copy Markdown
Collaborator

Summary

P2-1 (deferred in #211): cut the per-node constant of lui_flex so a
localized change no longer pays full style re-reads and measure re-calls
for every clean sibling in a recomputing column.

  • resolve_specs gets a fingerprint: percent-free specs resolve once,
    percent specs only when owner inner dims actually change; non-auto
    margin sums per axis are computed once at resolution.
  • set_position stores seed positions; each node records the offer
    that produced its measured dims (fin), the flex-site offers
    (prev_a/prev_b), its last evaluation context (ctx), and a
    resolution generation guarding staleness.
  • A conservative clean-child fast lane: clean children reuse flex
    bases, skip layout_node_internal calls whose offer provably equals
    the one that produced the current measured dims (guarded by
    resolution generation and parent direction), and skip re-seeding.
  • Pass-1 freeze scan skipped when no space to distribute; auto-margin
    scans skipped when no relative child has auto margins; the single-flex
    zero-basis reuse is gated on the sibling set being unchanged.

Benchmarks (100k child column, one child's height changes)

metric before after
Lui_flex relayout pass ~76-84 ms ~40-58 ms
Lui_flex frame two-pass relayout ~184-198 ms ~97-105 ms
Lui_layout.sync e2e relayout ~270-335 ms ~200-220 ms

End-to-end e2e measured via the perf harness (store patch + sync);
flex numbers from a standalone 100k-column benchmark.

Correctness

  • All 30 lui_flex tests, 22 lui_layout tests, and the full
    dune runtest suite (1099 checks) pass.
  • Differential fuzz: 1500 random trees × random mutations, comparing
    incremental relayout results between this engine and the previous
    one — zero mismatches. (Found and fixed along the way: seed staleness
    across a resolve in a measure pass, fin staleness across spec
    re-resolution, the single-flex zero-basis sibling dependency, and
    parent-direction sensitivity.)

Generated with Devin

tiensonqin and others added 5 commits October 13, 2026 08:04
…eeping

Cache the inputs the flex engine re-derives per child on every parent
layout pass:

- resolve_specs gains a fingerprint: percent-free specs never re-resolve,
  percent specs only when the owner's inner dims actually changed.
- Non-auto margin sums per axis are computed once at resolution
  (marg_row/marg_col) instead of re-walking the edge cascade.
- set_position stores the seeded slot values (pos_seed_*), letting a
  later pass place a child without re-running the seed math.
- Each node records the offer that produced its current measured dims
  (fin_*) plus the offers the flex-line call sites last made
  (prev_a_*/prev_b_*), the context those were taken under (ctx_*), and
  a resolution generation (res_gen) guarding staleness.

The skip gates are present but disabled in this commit; all
per-child work still runs, so layout results are bit-identical.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Turn the bookkeeping on: when a child is provably unaffected by its
siblings' changes (identical spec resolution, identical owner context,
relative flow, no auto margins, no wrapping), the parent skips the work
that would re-derive identical results:

- flex-basis reuse for definite or context-stable bases (guarded by
  was_sflex since the single-flex zero-basis depends on the sibling set)
- pass-1 freeze scan skipped when there is no space to distribute
- offer derivation + recursive call skipped at both flex-line sites
  when the offer equals the one that produced the current measured
  dims (fin/prev tracking, guarded by resolution generation and parent
  direction)
- auto-margin scans skipped when no relative child has auto margins

100k-column, one child height change: ~85ms -> ~45ms per relayout
pass; the two-pass frame relayout drops ~205ms -> ~91ms.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@tiensonqin
tiensonqin merged commit f1a079d into feat/ml-backend Oct 13, 2026
8 checks passed
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