Record retained extent-frame progress and remaining layout gap

This commit is contained in:
iris-ai committed 2026-09-17 16:41:06 -04:00
1 parent 035c7f20e8
commit 32151f7f9f
2 files changed
+83 -17

No files matched your search

+75 -16
View File
@@ -423,7 +423,7 @@ The original proposal was implemented by Claude as `5fcace1` on
`wip/region-and-placement` in `/home/bob/repos/iris-pr18`. It kept the fraction
reference stable but failed five layout cases and three draw-count cases.
The first correction is `efb416b`, exact recomposition is `2ed5503`, and the
current performance continuation is **`a7307d9`**, pushed to origin's
current performance continuation is **`c44bd19`**, pushed to origin's
`wip/region-and-placement`, in the isolated checkout
`/home/bob/repos/iris-layout-experiment`; **it is not on PR #18**. The original
checkout is unchanged. Keep the experiment's build directory separate: Cargo
@@ -517,22 +517,24 @@ regression fails with four draws instead of three when the optimization is
disabled.
**Still not ready to replace PR #18.** The prototype does substantially more
nested layout work than `e44dea3`, even after removing intermediate placements
(seed 1, depth 8):
nested layout work than `e44dea3`, even after retaining extent-relative child
frames (seed 1, depth 8):
| phase | widget draws at e44dea3 | current | primitive writes at e44dea3 | current |
| --- | ---: | ---: | ---: | ---: |
| cold | 369 | 484 | 9635 | 9179 |
| cold | 369 | 463 | 9635 | 9179 |
| repaint | 1 | 1 | 1 | 1 |
| many | 157 | 274 | 4721 | 5873 |
| size | 16 | 247 | 106 | 5200 |
| many | 157 | 263.1 | 4721 | 5873 |
| size | 16 | 240 | 106 | 5200 |
| scroll | 2 | 2 | 0 | 0 |
| resize | 13 | 292 | 0 | 5730 |
| resize | 13 | 278 | 0 | 5730 |
These are instrumented work counts, not speedups (50 frames per phase except
cold, which is one; 578 generated widgets, 191 finally active). Against
`2ed5503`, the changes remove 7 widget draws and 525 primitive writes per size
frame, and 8 draws and 525 writes per resize frame.
cold, which is one; 578 generated widgets, 191 finally active). The
measurement-only change at `7601aa2` removed 7 widget draws and 525
primitive writes per size frame, and 8 draws and 525 writes per resize frame,
relative to `2ed5503`. The extent-relative continuation below skips additional
container evaluations but does not reduce primitive writes.
**Measure cycles as well as instructions** (Bryan, 2026-09-17). The following
are whole-process medians from seven alternating before/after runs of direct,
@@ -578,7 +580,7 @@ executables under `perf stat -e cycles:u,instructions:u`, seed 1, depth 8,
All nine samples per side were retained; before/after cycle ranges do not
overlap. No scans or builds ran during measurement. All instrumented work
counters match `7601aa2` on all six phases (50 frames, cold once), including
the draw and primitive counts in the table above: this reduces the cost of
the primitive counts in the table above: this reduces the cost of
emitting the repeated glyphs, not the repeated layout evaluations themselves.
Additional depth-6 fixtures, nine alternating pairs and 4000 frames each:
@@ -602,14 +604,71 @@ saved under 0.8% of instructions and no cycles; special-casing equal endpoint
fractions in `UiSpan::within` cost 11% cycles and 7% instructions despite still
inlining. Keep that hot general composition small.
**Child frames can now follow the extent without evaluating their container.**
`widget_within` accepts the same `DrawRegion::{Frame, Extent}` reference as
primitives and masks. `Pad` retains its pixel inset in extent coordinates;
`Stack` inherits placement for its sizing child and retains extent-relative
frames for its other children. Moving the extent replays those requests through
`ask_box`, preserving child alignment and region nodes. This extends the existing
inherited-child walk rather than adding a separate layout body or a second cache.
It stores a region-bearing relation per extent-following child, so retained
child records are larger than the old widget-id-only list.
Two dependencies stay conservative. Fractional endpoints compose before pixel
evaluation, so their bounds cannot in general be pulled back through the extent
length alone; those frames still depend on raw placement. Reading a child's
fractional report also depends on placement because composing that report into
the parent's frame can change its value without changing the child's answer.
Pixel-inset frame bounds use the existing exact `Holds::through`.
**Keep the measured slot when repositioning.** A first trial recomputed it from
`active.size`, which is the final draw's report. Text measured narrow and placed
wider may report a different height at the latter width; the slot is still the
one chosen from measurement. Seed 20/depth 4 caught this. The retained slot is
now preserved on axes not explicitly assigned by the parent. A small synthetic
width-dependent widget pins the same failure without fonts.
Against `a7307d9`, seed 1/depth 8 skips 21 draws cold, 10.9 per `many` frame,
7 per size frame and 14 per resize frame. Repaint, scroll, and all primitive-write
counts are unchanged. Nine alternating pairs of direct uninstrumented release
executables under `perf stat -e cycles:u,instructions:u`, including setup:
| phase | median cycles before → after (billions) | median instructions before → after (billions) |
| --- | ---: | ---: |
| size (2000 frames) | 4.0819 → 4.0714 | 10.4107 → 10.4017 |
| resize (2000 frames) | 4.8108 → 4.7237 | 12.1854 → 11.9252 |
| many (2000 frames) | 4.7918 → 4.7787 | 12.0925 → 12.0567 |
| repaint (1,000,000 frames) | 2.6701 → 2.6851 | 6.0175 → 6.0195 |
| scroll (300,000 frames) | 2.6296 → 2.6273 | 6.5025 → 6.5817 |
Only resize establishes a cycle improvement: **1.8%**, with nonoverlapping sample
ranges, and 2.1% fewer instructions. Every other phase's cycle ranges overlap;
scroll uses 1.2% more instructions. All samples were retained and no scans or
builds ran during measurement. This is a small reduction in work, not closure of
the main gap.
Verification: workspace formatting, clippy with `layout-diagnostics`, tests
(104 suite tests, 21 core tests), exact release scans of 2000 seeds/depth 4 and
1000/depth 6, the shrinker over 400 trees/depth 5, and a debug scan of 120
seeds/depth 4 with assertions enabled.
The new no-redraw test checks nested padding/stacks, fixed child
alignment, primitives, masks, and region nodes; restoring the old container
calls makes it fail with three draws instead of two. Additional tests cover
fractional reports and numeric dependencies. All five reference renders match
`a7307d9` pixel for pixel at 1920x1200, and the resized 900x1200 `tabs` matches a
cold render there. The GPU probe reports Venus on the RX 7900 XT.
**The remaining gap has not been established as an unavoidable correctness
cost.** A temporary failure trace of one frame on seed 1, depth 8 counted
39/108 failed reuse attempts in size, 65/151 in resize, and 45/109 in many
cost.** Before the extent-relative change, a temporary failure trace of one
frame on seed 1, depth 8 counted 39/108 failed reuse attempts in size, 65/151 in resize, and 45/109 in many
where only the raw placement snapshot differed: both numeric frame and extent
ranges still held. Containers read that snapshot to construct child positions,
so discarding the check would be wrong; a way to retain those child positions
relative to the extent is the next protocol question. There is also necessary
width-dependent work: the hot text at widget 199 visits 68 px and 89.53613 px
so discarding the check would be wrong. Padding and stacks now retain their
extent-relative child frames, but `Span` still constructs its mixed-reference
slots from a raw placement read: along the row, child fractions refer to the
frame while cursor positions and leftover room refer to the extent. Retaining
those expressions without changing their fixed-point evaluation order is the
next protocol question. There is also necessary width-dependent work: the hot text at widget 199 visits 68 px and 89.53613 px
and reports different heights (316.80078 and 228.80078). It is evaluated
repeatedly at those widths, so that fact alone does not justify all the repeats.