Record what fixed point cost, and what it was
Three times slower in layout, and two thirds of that was a stacked child redrawing twice a frame rather than the arithmetic. The counters are what found it, once they could say "another layer" at all. The performance table is rewritten around the fixed-point commits and in milliseconds a frame, since the fixture it used has changed and the old instruction counts cannot be compared across it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d860587a4
commit
6081726314
1 file changed
+48
-16
+48
-16
@@ -8,7 +8,7 @@ log.
|
||||
|
||||
Canonical Iris `main` is **`ca2b4b2`** (#17, the headless rig). **#18
|
||||
`split/18-position-chain`** is open in `/home/bob/repos/iris-pr18`; its local
|
||||
head is **`bdab558`**, fifty-seven commits. Built-in alignment is complete there;
|
||||
head is **`f11f5f4`**, sixty commits. Built-in alignment is complete there;
|
||||
see "Built-in alignment" below for the retained-layout details. No PR reviews
|
||||
were present when checked on 2026-09-15.
|
||||
|
||||
@@ -72,12 +72,12 @@ rewrite:
|
||||
`core/src/ui/holds.rs`, the retained tests, and the generated cold-layout oracle
|
||||
pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
|
||||
|
||||
## Verification at `bdab558`
|
||||
## Verification at `f11f5f4`
|
||||
|
||||
- `cargo fmt --all --check`
|
||||
- `cargo build --workspace --all-features`
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
||||
- `cargo test --workspace --all-features`: 103 passed, 10 ignored
|
||||
- `cargo test --workspace --all-features`: 105 passed, 10 ignored
|
||||
- The release generated cold-layout oracle passed 100 seeds in 9.4 s, and a
|
||||
shrinker case at 300 seeds in 3.5 s: both run a thread per core but one.
|
||||
- The release shrinker passed **all five** cases -- `resize`, `repaint`,
|
||||
@@ -120,24 +120,51 @@ choice and the incompatible visual effect of making `Full` the default.
|
||||
|
||||
### Performance
|
||||
|
||||
The retained rewrite was compared with #18's previous head `691e3eb` using the
|
||||
same release `layout_diagnostics` fixture, seed 1, depth 8, 500 frames, 130
|
||||
dirty widgets:
|
||||
Measured 2026-09-16 on the release `layout_diagnostics` fixture, seed 1,
|
||||
depth 8, 500 frames, as median milliseconds a frame. `5ed9e87` is the commit
|
||||
before fixed point; `39e4ca2` is fixed point complete.
|
||||
|
||||
| phase | `691e3eb` | `29c7881` |
|
||||
| --- | ---: | ---: |
|
||||
| many | 25.17M instructions/frame | 6.14M |
|
||||
| resize | 16.08M | 8.39M |
|
||||
| scroll | 0.720M | 0.691M |
|
||||
| repaint | 0.720M | 0.689M |
|
||||
| size | 0.730M | 0.698M |
|
||||
| phase | `5ed9e87` | `39e4ca2` | `f11f5f4` |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| many | 0.179 ms | 0.544 | 0.278 |
|
||||
| resize | 0.020 | 0.035 | 0.041 |
|
||||
| scroll | 0.011 | 0.030 | 0.020 |
|
||||
| repaint | 0.012 | 0.031 | 0.028 |
|
||||
|
||||
The final `29c7881` measurements were 3,070,693,965 instructions for 500
|
||||
`many` frames and 4,192,804,214 for 500 `resize` frames. Re-run before quoting
|
||||
tighter figures.
|
||||
**Fixed point cost 3x, and two thirds of that was not the grid.** The
|
||||
counters said eight more "placed by redrawing" a frame in `scroll`, all of
|
||||
them "reuse: another layer": a retained drawing belongs to the layer it was
|
||||
made on, and `Stack` measured the child that sizes it on its own layer before
|
||||
drawing it again on the child layer. `97cc8b3` measures on the layer the
|
||||
child ends up on, which puts the scroll phase's counters back exactly where
|
||||
they were -- 4 widget draws, 12 draw requests.
|
||||
|
||||
What is left is per-operation cost, not more work: at `f11f5f4` the `many`
|
||||
phase does 125 widget draws against 121 before, and takes 1.6x as long. The
|
||||
arithmetic is the difference -- an `i64` multiply and a rounding branch where
|
||||
there was an `f32` multiply. The profile's shape, in order: `InstanceList::
|
||||
push`, `Painter::glyphs`, `RegionRemap::apply_span`, `UiRegion::within`. The
|
||||
one obvious thing left is `glyphs`, which converts four `f32`s per glyph:
|
||||
a `GlyphEntry` holding `Px` would convert once when the glyph is rasterised
|
||||
instead of on every frame that draws it.
|
||||
|
||||
Earlier, against #18's own history: the retained rewrite took `many` from
|
||||
25.17M instructions a frame at `691e3eb` to 6.14M at `29c7881`, and `resize`
|
||||
from 16.08M to 8.39M. That fixture has since changed; do not compare across
|
||||
it.
|
||||
|
||||
## Retained-layout invariants
|
||||
|
||||
- **A retained drawing belongs to the layer it was made on.** Asked for again
|
||||
on another layer it is redrawn, since nothing about its geometry says it is
|
||||
in a list that paints at a different moment. A container that measures a
|
||||
child by drawing it therefore measures on the layer that child will draw on
|
||||
-- `Painter::child_layer_at` addresses one -- or it pays two draws a frame
|
||||
forever and keeps whichever the second ask left.
|
||||
- A widget that clips its contents to its box reports its box: `Scroll` and
|
||||
`Masked` both report `LEFTOVER`, and a `debug_assert` in `draw_at` holds
|
||||
any widget that set a mask to it. Overflowing is otherwise ordinary and a
|
||||
text too tall for its box says so.
|
||||
- A span is as long across itself as its longest child, unless a rule beside
|
||||
it says how long it is -- and then it does not read its children there at
|
||||
all, since the answer is not wanted and reading one is what makes its size
|
||||
@@ -458,6 +485,11 @@ the same `Holds` contract and box chain.
|
||||
|
||||
Queued from this work, in order:
|
||||
|
||||
- `Painter::glyphs` converts four `f32`s to `Px` per glyph, every frame that
|
||||
draws it. A `GlyphEntry` holding `Px` would convert once, when the glyph is
|
||||
rasterised. It is the largest single thing left in the layout profile after
|
||||
`InstanceList::push`.
|
||||
|
||||
- `Scroll` should take a direction rather than one axis: vertical, horizontal,
|
||||
or both. Reporting `LEFTOVER` on both axes is already the right shape for it.
|
||||
- Restore `max_width`/`max_height` as `SizeRule::{Min, Max, Clamp}`. `8220a78`
|
||||
|
||||
Reference in new issue
Block a user