Record what wrapping saved, and the rounding question left open

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Fable 5.1 committed 2026-09-16 14:23:22 -04:00
1 parent 9ed90505b3
commit 663a95f4a2
1 file changed
+35 -11
+35 -11
View File
@@ -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 **`394d514`**, seventy commits. Built-in alignment is complete there;
head is **`4febabf`**, seventy-one 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.
@@ -91,6 +91,11 @@ pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
## Verification at `394d514`
`4febabf` on top of it -- `Fixed` wrapping rather than saturating -- passed
the workspace tests with all features (105), the release 100-seed oracle in
9.5 s, and rendered `random`, `tabs` and `text` byte-identical at 1920x1200
against `394d514`. The measurements are under "Performance".
- `cargo fmt --all --check`
- `cargo build --workspace --all-features`
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
@@ -160,9 +165,14 @@ Measured on the fixed-shape fixture, seed 1, depth 8, 500 frames of `many`:
| --- | ---: | ---: | ---: | ---: |
| `5ed9e87`, before fixed point | 100 | 4,272 | 1,761M | ~699M |
| `4cbb242` | 97 | 3,951 | 2,093M | ~819M |
| `4febabf`, wrapping | 97 | 3,951 | 1,918M | ~771M |
So the grid costs something like a fifth to a quarter, on a head that draws
slightly less. Normalised by primitive writes it is about 1.27x.
Normalised by primitive writes the grid is now about 1.18x the float head
on instructions and 1.19x on cycles; per drawn widget it is 1.12x. What is
left is the shape of an integer multiply with a rounding against a float
fused multiply-add, spread across `UiSpan::within` (4.7% of cycles),
`remap_subtree` and `Holds::through`; nothing in the profile above those
is the grid. Text line breaking is 10% and `InstanceList::push` 9%.
**Cycles are measurable on this machine and instructions alone are not
enough.** Three runs of one binary varied 0.23%. It is *wall time* that
@@ -200,12 +210,22 @@ Tried and rejected, with numbers, so they are not tried again:
- Short-circuiting `apply_scalar` where the fraction is nought or one: +17%.
(From the previous session.)
**The one lever left that is worth a decision:** `Fixed`'s `saturating_add`
and `saturating_sub`, measured at **8.1% of instructions and 2.7% of
cycles**. Wrapping instead is one instruction where saturating is five. That
trades away "a clamped coordinate keeps the ordering a wrapped one inverts",
which is a posture rather than a micro-optimisation, so it needs Bryan.
Everything else is spread thin.
- `#[inline]` on `UiSpan::within`, whose prologue and epilogue were a sixth
of its own cycles: -0.2% instructions, **+1.5% cycles**.
**`4febabf` makes `Fixed` wrap rather than saturate** (Bryan, 2026-09-16: a
coordinate past the range is not going to draw reasonably anyway, so wrap
and break clearly): -8.6% instructions, -6.6% cycles, more on cycles than
the 2.7% the instruction share predicted. `from_f32` still clamps and
`Holds` keeps its saturating `narrow`, since a range of box lengths past
`i32` really is unbounded.
**One posture question is still open, with its number.** `shift_round`
rounds halves away from zero so a value and its negation round to the same
distance, which is a sign branch on every multiply. Rounding halves up
instead measured **-1.6% instructions, -2% cycles** (1,888M, ~757M), and
would let a flipped span land a step from its mirror image at exact halves.
Not applied; Bryan's call.
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`
@@ -417,8 +437,12 @@ pixels and `Holds`. Decided with Bryan on 2026-09-15.
- A weight is not a fraction: a list divides its room by the total of its
weights, so `Weight` trades precision for the range to hold a whole list,
and `Rel::ratio` turns two weights into a share on the finer grid.
- **Arithmetic saturates rather than wrapping**, because a clamped coordinate
keeps the ordering a wrapped one inverts.
- **Arithmetic wraps, as of `4febabf`.** It saturated first, so that a
clamped coordinate kept the ordering a wrapped one inverts, and that cost
a twelfth of layout's instructions to keep order two million pixels out
where nothing draws. `MIN` and `MAX` still stand in for an unbounded end,
which is safe only because every use compares against them and none adds
to them; `from_f32` is the one operation that clamps.
- `Px` was `1/64` first. The residue of a length reached two ways is one
rounding, so it scales with the step: at `1/64` that was 0.016 px, enough
to move a box, and at `1/1024` it is a thousandth of a pixel. Range is