Record what carrying the depth cost and what is left

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-14 20:10:39 -04:00
1 parent ba97265191
commit 2a40aa01db
1 file changed
+18 -4
+18 -4
View File
@@ -409,10 +409,24 @@ today it is O(dirty x depth) per widget settled. It wants agreeing first: every
place that inserts into or removes from `needs_redraw` has to pair with it, and place that inserts into or removes from `needs_redraw` has to pair with it, and
a count that is too low is a stale size rather than a slow frame. a count that is too low is a stale size rather than a slow frame.
Of the sort's own 24.5%, about 15 points are the depth walk and about 9 are `3f7cd82` takes most of it without touching the order: a widget's depth is
iterating the `HashSet`, which walks by capacity rather than by length. Keeping known where it is drawn -- its parent's plus one -- so `Painter` carries it and
the depth on `ActiveData` would remove the first without changing the order at `ActiveData` keeps it, and the choice reads a field instead of walking an
all, at the price of a second source of truth for it. ancestry. Being reused counts as being visited, so the two reuse paths keep it
current; only a subtree nothing looked at can hold an old one, and nothing
under an unvisited subtree is being ordered. `depth` asserts the kept value
against the ancestry in debug builds, and the hundred-seed sweep passes with
those assertions on, reshuffles included -- those being what moves a widget to
another parent. Same load at 130 of 260 dirty: 8.16M instructions per frame to
7.14M, median 0.813 ms to 0.639, and the choosing from 25.8% of the frame to
4.7%.
What is left of it is iterating the dirty set, which a `HashSet` walks by
capacity rather than by length. Ordering it -- a `BTreeSet` keyed by the kept
depth, or a bucket per depth -- would take that too, but `needs_redraw` lives
on `Widgets` and is inserted from places with no view of the tree, so either
means a second structure inside the render state kept in step with it. For 4.7%
that is not obviously worth the coupling.
**A frame that dirties many widgets at once was not being checked, and it is **A frame that dirties many widgets at once was not being checked, and it is
where the settle order shows.** `77bb75e` adds two generated cases -- every where the settle order shows.** `77bb75e` adds two generated cases -- every