Incremental text: parley cannot, the app already does it, and the 9.5ms is the fixture
Iris asked to look into incremental text rendering, hoping parley supported it. It does not, by design: a `Layout` re-linebreaks and re-aligns freely but "if the text content or the styles applied to that content change then a new `Layout` must be created", its LRU cache holds harfrust's per-font shaper data rather than shaped runs, and its own `PlainEditor` rebuilds the whole layout from the whole buffer on every keystroke. The app already does what incremental layout would buy: `RowBlocks:: apply_delta` keeps one `TextEdit` per markdown block and re-shapes only the one a delta landed in. Re-splitting the markdown to find it is 18µs at 18,000 characters; comparing the blocks is 470ns. What is left is one `TextBuffer::shape` of that block, linear in its length at ~0.23ms per 1,000 characters here -- and the bench fixture's streamed message is 14,888 characters in a *single* block, a run-on paragraph with no blank line in it, so every delta reshapes all of it. That is 3.5ms of the measured 3.86ms frame. Real replies are not that: across 7,706 top-level blocks from 3,675 real assistant messages on this machine (lengths only, no content copied anywhere), p50 147 characters, p90 449, p99 836, largest 1,580, nothing above 4,000; code fences p50 126, largest 589. At those sizes a reshape is 48µs to 372µs here, roughly 0.12-0.93ms on the phone -- inside a 120Hz budget with no incremental anything. So the recommendation is not to build it, and to give the fixture's streamed message the paragraph structure a real reply has instead. Three runs added to `frame_profile.rs` so none of this is re-derived: what reshaping a growing message costs (including at the sizes real replies reach), where a delta's cost is, and what the fixture actually streams. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9bf714fa2e
commit
43a3a345e4
3 files changed
+219
-9
No files matched your search
@@ -405,12 +405,19 @@ Each exists because something was invisible without it.
|
||||
transcript -- every later pass over the same rows is p99 0.26ms. A
|
||||
**streamed event** is, and it is not where it looks: folding the event
|
||||
is 0.35ms and applying the diff to the widget tree is 0.41ms, while the
|
||||
*frame* is 3.86ms here and 9.5ms on Iris's phone. 401 streamed events
|
||||
move the item count from 652 to 654, so almost every one is a delta
|
||||
into the same row -- the cost is re-laying out and re-shaping one
|
||||
growing message on every delta, not the fold. (The fold was the
|
||||
*frame* is 3.86ms here and 9.5ms on Iris's phone. (The fold was the
|
||||
hypothesis, from `foldEvent`'s Compose lesson under "Things that have
|
||||
bitten"; measuring it is what ruled it out.)
|
||||
bitten"; measuring it is what ruled it out.) That frame is one
|
||||
`TextBuffer::shape` of the block a delta landed in, and **the fixture's
|
||||
is 14,888 characters in a single block** -- against a largest-ever
|
||||
1,580 across 7,706 blocks of real replies. So the stream phase's number
|
||||
is a property of the fixture, not of streaming; docs/RUST.md's
|
||||
"Incremental text" has the measurements and why parley cannot help.
|
||||
|
||||
The last two runs (`where_a_streamed_deltas_cost_is`,
|
||||
`what_the_fixture_streams`) exist to keep that answerable: what a delta
|
||||
costs to re-split and re-compare, and what the fixture actually
|
||||
streams.
|
||||
- **The emulator is a GLES rig, deliberately** (Iris, 2026-09-08;
|
||||
docs/RUST.md). Its guest has no hardware Vulkan -- only SwiftShader
|
||||
in software -- while its GLES *is* the host's real GPU through virgl at
|
||||
|
||||
Reference in new issue
Block a user