Measure step 5's span pin and say what blocks the sound version
Re-measured the work counters at a888717 (unchanged from adbedaf), and tested the handoff's claim about a positive span pinning `far`: without the pin, seed 1's resize goes from 44 draws of 13 widgets to 20 of 9. The pin is worth removing, and what stops a sound removal is that no `Part` can say "from the cursor to the end of the box" without naming the box's length.
This commit is contained in:
1 parent
2fa734cd63
commit
1ef31bc9e7
1 file changed
+46
-5
+46
-5
@@ -254,7 +254,7 @@ Unchanged; see `docs/LAYOUT.md`.
|
|||||||
## Implementation plan
|
## Implementation plan
|
||||||
|
|
||||||
Work in `/home/bob/repos/iris-layout-experiment` on `wip/one-ask` from
|
Work in `/home/bob/repos/iris-layout-experiment` on `wip/one-ask` from
|
||||||
`a30971e`. Make each step a warning-clean commit and run its named checks
|
`a888717`. Make each step a warning-clean commit and run its named checks
|
||||||
before the next. If a step exposes a different mechanism, stop and update
|
before the next. If a step exposes a different mechanism, stop and update
|
||||||
this handoff rather than papering over it.
|
this handoff rather than papering over it.
|
||||||
|
|
||||||
@@ -302,9 +302,11 @@ is worth a name.
|
|||||||
### 5. Restore the expected retained cost
|
### 5. Restore the expected retained cost
|
||||||
|
|
||||||
Work counters, seed 1 and 13, depth 8, widget draws / distinct widgets,
|
Work counters, seed 1 and 13, depth 8, widget draws / distinct widgets,
|
||||||
beside `e44dea3` (#18) and `0ef87eb` (before the frame became a length):
|
beside `e44dea3` (#18) and `0ef87eb` (before the frame became a length). The
|
||||||
|
`a888717` column was re-measured after the step 1 review and is identical to
|
||||||
|
`adbedaf` at every phase, so the scroll fix cost nothing:
|
||||||
|
|
||||||
| seed 1 | e44dea3 | 0ef87eb | adbedaf |
|
| seed 1 | e44dea3 | 0ef87eb | a888717 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| cold | 369/261 | 331/288 | 342/288 |
|
| cold | 369/261 | 331/288 | 342/288 |
|
||||||
| many | 157/95 | 110/92 | 118/95 |
|
| many | 157/95 | 110/92 | 118/95 |
|
||||||
@@ -312,12 +314,21 @@ beside `e44dea3` (#18) and `0ef87eb` (before the frame became a length):
|
|||||||
| scroll | 2 | 1 | 1 |
|
| scroll | 2 | 1 | 1 |
|
||||||
| resize | 13/13 | 40/15 | 44/13 |
|
| resize | 13/13 | 40/15 | 44/13 |
|
||||||
|
|
||||||
| seed 13 | e44dea3 | 0ef87eb | adbedaf |
|
| seed 13 | e44dea3 | 0ef87eb | a888717 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| cold | 1330/707 | 1179/982 | 1278/982 |
|
| cold | 1330/707 | 1179/982 | 1278/982 |
|
||||||
| many | 524/159 | 424/364 | 429/366 |
|
| many | 524/159 | 424/364 | 429/366 |
|
||||||
| resize | nothing | nothing | nothing |
|
| resize | nothing | nothing | nothing |
|
||||||
|
|
||||||
|
The command is
|
||||||
|
|
||||||
|
```sh
|
||||||
|
IRIS_SEED=1 IRIS_DEPTH=8 cargo test --release --features layout-diagnostics \
|
||||||
|
--test layout_diagnostics -- --ignored --nocapture layout_cost
|
||||||
|
```
|
||||||
|
|
||||||
|
reading `widget draws` and `distinct widgets` from each phase's block.
|
||||||
|
|
||||||
`many`, `size` and `scroll` are better than #18 and within a few draws of
|
`many`, `size` and `scroll` are better than #18 and within a few draws of
|
||||||
`0ef87eb`; `cold` is 3% and 8% more than `0ef87eb` for the same distinct
|
`0ef87eb`; `cold` is 3% and 8% more than `0ef87eb` for the same distinct
|
||||||
widgets, which is the frame pins making a widget answer again where it used
|
widgets, which is the frame pins making a widget answer again where it used
|
||||||
@@ -348,7 +359,37 @@ Three mechanisms behind what is left, all understood:
|
|||||||
- **A positive-direction span with no shares pins `far`** it does not need,
|
- **A positive-direction span with no shares pins `far`** it does not need,
|
||||||
so a resize redraws it. Read `extent_len` only where a slot depends on it
|
so a resize redraws it. Read `extent_len` only where a slot depends on it
|
||||||
(shares, or `Sign::Neg`), and express the measuring room's far end without
|
(shares, or `Sign::Neg`), and express the measuring room's far end without
|
||||||
the length. Measure `resize` at seed 1 before and after.
|
the length.
|
||||||
|
|
||||||
|
**Measured at `a888717` (worker, 2026-09-19)**, by replacing `far` with a
|
||||||
|
deliberately unsound read that returns the length without pinning: seed 1's
|
||||||
|
`resize` goes from **44 draws of 13 distinct widgets to 20 of 9**, and the
|
||||||
|
median frame from 0.063 ms to 0.022 ms. So the pin is worth the step, and
|
||||||
|
it is the pin rather than the twice-asked multiplication -- the hottest
|
||||||
|
widgets are drawn 8, 8, 4, 4, 4, 4, 2, 2 times, and only 3 of 98 reuse
|
||||||
|
attempts are rejected by a frame length. A symbolic pin fails on a resize
|
||||||
|
because a symbolic length is not window-independent: a scroll's content box
|
||||||
|
is `rel 0, px content_len`, and `content_len` is measured against the
|
||||||
|
window.
|
||||||
|
|
||||||
|
**What blocks the sound version.** The measuring room is
|
||||||
|
`Part::From(UiSpan::new(cursor, far))`, and no existing `Part` says "from
|
||||||
|
the cursor to the end of the box" without naming the box's length. A new
|
||||||
|
variant would -- an inset of `lead` and `trail` *window* lengths, which
|
||||||
|
also subsumes `Part::Of`'s pure-pixel use in `Pad` -- but `in_parent` needs
|
||||||
|
an arm for it, and the mapping is not a plain `Holds::through`: the inset
|
||||||
|
is a window length, so the child's box length changes with the window and
|
||||||
|
the offset cannot be written as a `Len` of the parent's box.
|
||||||
|
|
||||||
|
There is a second, deeper question under it. Dropping the pin is only
|
||||||
|
sound if nothing else has to notice the span's box changing, and today
|
||||||
|
`in_parent`'s `_` arm converts a child's box range into a range on the
|
||||||
|
*window* through the child's box length -- which assumes that length is a
|
||||||
|
fixed expression of the window, which is exactly what `far` changing
|
||||||
|
violates. Putting that dependency on the parent's own box instead would
|
||||||
|
let the span stop reading `far` for soundness and read it only where a
|
||||||
|
slot depends on it, but it will also invalidate more elsewhere. Decide
|
||||||
|
that before writing the `Part` variant.
|
||||||
- **A rule that is a fraction of the frame pins the frame**, which is what
|
- **A rule that is a fraction of the frame pins the frame**, which is what
|
||||||
`cold` grew by. The answer for such an axis is a pure function of the rule
|
`cold` grew by. The answer for such an axis is a pure function of the rule
|
||||||
and the frame, so a reuse could resolve it again from the record instead
|
and the frame, so a reuse could resolve it again from the record instead
|
||||||
|
|||||||
Reference in new issue
Block a user