From 2a40aa01db6571ba2b103d478a7699ba6ecae82e Mon Sep 17 00:00:00 2001 From: iris-ai <4+iris-ai@noreply.localhost> Date: Mon, 14 Sep 2026 20:10:39 -0400 Subject: [PATCH] Record what carrying the depth cost and what is left Co-Authored-By: Claude Opus 5 --- docs/IRIS_EXTRACTION_HANDOFF.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/IRIS_EXTRACTION_HANDOFF.md b/docs/IRIS_EXTRACTION_HANDOFF.md index 2a4cc17..b967406 100644 --- a/docs/IRIS_EXTRACTION_HANDOFF.md +++ b/docs/IRIS_EXTRACTION_HANDOFF.md @@ -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 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 -iterating the `HashSet`, which walks by capacity rather than by length. Keeping -the depth on `ActiveData` would remove the first without changing the order at -all, at the price of a second source of truth for it. +`3f7cd82` takes most of it without touching the order: a widget's depth is +known where it is drawn -- its parent's plus one -- so `Painter` carries it and +`ActiveData` keeps it, and the choice reads a field instead of walking an +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 where the settle order shows.** `77bb75e` adds two generated cases -- every