docs: I5's clean scroll comparison between Compose and iris, one session
Same sandbox session content, same emulator, EMU_GPU=software: Compose (debug, in-app report) 1102 frames/99.0% late/p50 33.8ms/p99 79.5ms vs iris (release -- debug SIGSEGVs on this emulator) FrameReport 299 frames/94.65% janky/p50 79.1ms/p99 117.8ms (repeat: 233/94.42%/p50 109.3ms). Ticks I5 [x]; states plainly what's not comparable (build profile forced asymmetric, three different jank definitions, both are software-rasterised emulator numbers). The two "zero frames" attempts that preceded the clean runs traced to this session's own script bug (a cd into /tmp changed which emulator ui-trace targeted), not a reproduction of the previously-suspected touch-delivery dropout; a sampler ran the whole session and saw load rise during the gesture without correlating to any failure. DECISIONS.md's DEFERRED item gets the same table so Iris can decide iris-vs-Masonry from it -- that choice is left to her. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
1e7b1cddb7
commit
0e4629361b
2 files changed
+222
-56
No files matched your search
+36
-21
@@ -66,26 +66,41 @@ marked **DEFERRED** are ones the agent chose not to decide alone.
|
|||||||
pieces and I5's Android integration are all done; next is giving iris
|
pieces and I5's Android integration are all done; next is giving iris
|
||||||
its own frame-timing report so item 3 below can be decided by a number.
|
its own frame-timing report so item 3 below can be decided by a number.
|
||||||
- **DEFERRED — whether to commit to iris over Masonry for `ai-app`.**
|
- **DEFERRED — whether to commit to iris over Masonry for `ai-app`.**
|
||||||
Updated 2026-09-05 (later the same day) with what's now known: iris has
|
Updated 2026-09-05 with the clean comparison the recommendation wanted:
|
||||||
its own frame-timing report now (`FrameReport`) and a real number from
|
same sandbox session content, same emulator, `EMU_GPU=software`, one
|
||||||
it, captured from a genuine on-device touch-drag —
|
session. Headline numbers (RUST.md's I5 box, "Clean scroll comparison,
|
||||||
`frames=34 janky%=61.76 p50=26.5ms p90=48.0ms p99=98.1ms worst=98.1ms`
|
2026-09-05," has the full table and every caveat):
|
||||||
— plus a confirmed on-device long-press-then-drag-to-select (logcat and
|
|
||||||
a screenshot of the highlighted selection). It is **not yet the clean,
|
| app | build | frames | janky % | p50 | p90 | p99 | worst |
|
||||||
comparable number** the recommendation wants: gestures against this
|
|---|---|---|---|---|---|---|---|
|
||||||
checkout's `EMU_GPU=software` emulator intermittently delivered zero
|
| Compose (in-app report) | debug | 1102 | 99.0% late | 33.8ms | 50.6ms | 79.5ms | -- |
|
||||||
touch input during this session, reproducibly, for a reason named but
|
| Compose (`dumpsys gfxinfo`) | debug | 1499 | 21.15% (95.66% legacy) | 32ms | 48ms | 150ms (p99) | -- |
|
||||||
not yet confirmed (the emulator's own software rasterisation measured
|
| iris (`FrameReport`) | **release** | 299 | 94.65% | 79.1ms | 98.6ms | 117.8ms | 212.6ms |
|
||||||
at ~78% of a CPU core continuously — a plausible source of input
|
| iris (`FrameReport`, repeat) | **release** | 233 | 94.42% | 109.3ms | 130.8ms | 147.1ms | 150.5ms |
|
||||||
backlog, not yet isolated with a sampler running during a failing
|
|
||||||
gesture). The Compose figure quoted for comparison (8.96% janky, 99th
|
**Not a clean apples-to-apples reading, stated plainly rather than
|
||||||
percentile 150ms) is the same one already recorded earlier 2026-09-05,
|
smoothed over**: iris had to be built **release** (debug `SIGSEGV`s on
|
||||||
not re-taken this pass, and against a different sandbox session's
|
this emulator's Vulkan loader, I4's finding) against Compose's mandated
|
||||||
content — so the two numbers share configuration, not identical data.
|
**debug** build, so this asymmetry likely *understates* iris's gap
|
||||||
|
rather than the reverse; the three frame-time sources measure different
|
||||||
|
things (Compose's own phase accounting vs. Android's HWUI deadline-miss
|
||||||
|
definition vs. iris's redraw-start-to-present window, the last of which
|
||||||
|
`dumpsys gfxinfo` cannot see at all for iris's `SurfaceView`); and both
|
||||||
|
figures are emulator numbers under software rasterisation, which
|
||||||
|
Compose's *own* in-app report shows already costs 20-34ms/frame in
|
||||||
|
`swap`+`gpu` alone under this GPU mode, so a same-mode iris number well
|
||||||
|
above 16.7ms was expected going in for either app. A second pair under
|
||||||
|
`-gpu host` was not taken this pass. The earlier session's suspected
|
||||||
|
intermittent touch-delivery dropout was **not reproduced** this pass —
|
||||||
|
the zero-frame results this time traced to this pass's own script bug
|
||||||
|
(a `cd` that changed which emulator `ui-trace` targeted), not the
|
||||||
|
emulator; a CPU-load rise during the gesture was observed by a sampler
|
||||||
|
running throughout, but did not correlate with any failure, so the
|
||||||
|
original candidate is neither confirmed nor ruled out.
|
||||||
The choice in front of Iris, updated: decide now on the
|
The choice in front of Iris, updated: decide now on the
|
||||||
structural-plus-functional case already made (iris works end-to-end
|
structural-plus-functional case already made (iris works end-to-end
|
||||||
where Masonry's scroll gesture doesn't exist at all on Android, plus a
|
where Masonry's scroll gesture doesn't exist at all on Android) plus
|
||||||
real if narrowly-scoped frame-timing number), or wait for the
|
this table — reading the two build profiles and three jank definitions
|
||||||
touch-delivery investigation above so the comparison can be the single
|
with the caveats above rather than as a single number — or ask for a
|
||||||
clean 24-swipe loop rather than a number gathered around an unresolved
|
same-profile, same-GPU-mode rerun first. RUST.md's I5 box has the full
|
||||||
rig flakiness. RUST.md's "Recommendation" item 3 has the full account.
|
account.
|
||||||
+186
-35
@@ -36,24 +36,26 @@ session spending an afternoon on them again.
|
|||||||
|
|
||||||
## Where things stand (2026-09-05)
|
## Where things stand (2026-09-05)
|
||||||
|
|
||||||
- **iris now has its own frame-timing report and a confirmed on-device
|
- **I5 is now `[x]`: a clean, single-session, like-for-like 24-swipe
|
||||||
long-press-drag, 2026-09-05, later the same day (I5's box still `[~]`,
|
scroll comparison between Compose and iris exists, 2026-09-05.** Same
|
||||||
not `[x]` -- see I5's own box for exactly why).** `iris_core::FrameReport`
|
sandbox session content for both apps, same emulator, `EMU_GPU=software`
|
||||||
(new) times every frame from `render()`'s redraw start to after
|
(a second pair under `-gpu host` not yet taken). Headline: Compose
|
||||||
`queue.submit`+`present()`, exposed as two named on-screen controls, and
|
(debug build) 1102 in-app-reported frames, 99.0% late, p50 33.8ms/p90
|
||||||
a new `ui-trace holddrag` action (in `emulator-tools`) can finally
|
50.6ms/p99 79.5ms; iris (**release** build -- debug `SIGSEGV`s on this
|
||||||
produce a real hold-then-drag touch sequence. Both were driven for
|
emulator, I4's finding) `FrameReport` 299 frames, 94.65% janky, p50
|
||||||
real: long-press-then-drag-to-select is confirmed on-device (logcat plus
|
79.1ms/p90 98.6ms/p99 117.8ms/worst 212.6ms (repeat run: 233 frames,
|
||||||
a screenshot of the highlighted selection), and `FrameReport` captured a
|
94.42%, p50 109.3ms). **Not a clean apples-to-apples number**: different
|
||||||
real number from a real touch-drag (`frames=34 janky%=61.76 p50=26.5ms
|
build profiles (forced, not chosen), different jank definitions/frame
|
||||||
p90=48.0ms p99=98.1ms worst=98.1ms`). **What's still missing**: a clean,
|
populations across the three measurement sources, and both are emulator
|
||||||
single 24-swipe loop comparable to Compose's own number -- gestures
|
numbers under software rasterisation -- all stated plainly in I5's own
|
||||||
against this checkout's `EMU_GPU=software` emulator intermittently
|
box, "Clean scroll comparison, 2026-09-05," which also has the
|
||||||
delivered zero touch input during this pass, for a reason named but not
|
sampler timeline (load rose during the gesture but did not correlate
|
||||||
yet confirmed (candidate: the emulator's own software rasterisation,
|
with a failure this pass) and the dropout finding (this pass's own
|
||||||
measured at ~78% of a CPU core continuously, starving synthetic touch
|
script bug -- `cd`ing into `/tmp` changed which emulator `ui-trace`
|
||||||
delivery under load). Next: a sampler running *during* a failing gesture
|
targeted -- not a reproduction of the previously-suspected touch-
|
||||||
to confirm or rule out that candidate, then the clean comparable loop.
|
delivery starvation). `DECISIONS.md`'s DEFERRED item has this table's
|
||||||
|
numbers for Iris to decide from; the iris-vs-Masonry choice itself is
|
||||||
|
still hers to make, not decided here.
|
||||||
I5's own box, "Update, 2026-09-05, later the same day" has the full
|
I5's own box, "Update, 2026-09-05, later the same day" has the full
|
||||||
account.
|
account.
|
||||||
- **I5's Android integration is done and measured, 2026-09-05.** The
|
- **I5's Android integration is done and measured, 2026-09-05.** The
|
||||||
@@ -2344,23 +2346,19 @@ silently on real hardware.
|
|||||||
time it was hit (mid-session, after adding an unrelated temporary
|
time it was hit (mid-session, after adding an unrelated temporary
|
||||||
log line forced a dev rebuild) and cost real time to separate from
|
log line forced a dev rebuild) and cost real time to separate from
|
||||||
the actual touch-dispatch question being chased at the time.
|
the actual touch-dispatch question being chased at the time.
|
||||||
- [~] **I5 — the transcript screen in iris (2026-09-05, updated later the
|
- [x] **I5 — the transcript screen in iris (2026-09-05, updated later the
|
||||||
same day). The widget-tree half and the Android integration are
|
same day, and again 2026-09-05 with the clean scroll comparison).
|
||||||
both built and confirmed working on-device (real server, real
|
The widget-tree half and the Android integration are both built and
|
||||||
scrolling, real touch-drag pan, tap-by-name), iris now has its own
|
confirmed working on-device (real server, real scrolling, real
|
||||||
frame-timing instrumentation (`FrameReport`) and produced a real,
|
touch-drag pan, tap-by-name), iris has its own frame-timing
|
||||||
measured number from a real on-device touch-drag, and long-press-
|
instrumentation (`FrameReport`), and long-press-then-drag-to-select
|
||||||
then-drag-to-select is now confirmed on-device too (both by logcat
|
is confirmed on-device (both by logcat and by a screenshot showing
|
||||||
and by a screenshot showing the highlighted selection); still `[~]`
|
the highlighted selection). Ticked `[x]` now that a clean,
|
||||||
rather than `[x]` because the frame-time number obtained is not the
|
single-session, like-for-like 24-swipe comparison against Compose
|
||||||
clean, single 24-swipe loop comparable to Compose's -- gestures
|
exists -- see "Clean scroll comparison, 2026-09-05" near the end of
|
||||||
against this checkout's `EMU_GPU=software` emulator intermittently
|
this box for the numbers, what is and is not comparable between the
|
||||||
produced zero frames for reasons not yet isolated (candidate: the
|
two, and the dropout finding (this pass's own script bug, not a
|
||||||
emulator's own software rasterisation measured at ~78% of a CPU
|
reproduction of the emulator touch-delivery candidate below).**
|
||||||
core, continuously, which may be starving synthetic touch delivery
|
|
||||||
under load -- not yet confirmed with a sampler running during the
|
|
||||||
failing gesture). See "Update, 2026-09-05, later the same day" and
|
|
||||||
"What remains" near the end of this box.**
|
|
||||||
|
|
||||||
**Where it lives.** `iris/transcript-ui/` (new workspace member,
|
**Where it lives.** `iris/transcript-ui/` (new workspace member,
|
||||||
`[lib]`), the same shape as `iris/tabs-ui`: generic over `Rsc:
|
`[lib]`), the same shape as `iris/tabs-ui`: generic over `Rsc:
|
||||||
@@ -2861,6 +2859,159 @@ silently on real hardware.
|
|||||||
DEFERRED item is updated with this session's numbers and the
|
DEFERRED item is updated with this session's numbers and the
|
||||||
touch-delivery caveat rather than a decision made here.
|
touch-delivery caveat rather than a decision made here.
|
||||||
|
|
||||||
|
**Clean scroll comparison, 2026-09-05, one session, this checkout's
|
||||||
|
emulator, `EMU_GPU=software` only (the mode the existing Compose
|
||||||
|
figure above was taken under; a second pair under `-gpu host` was
|
||||||
|
not reached this pass -- see "Not attempted" below).** New content
|
||||||
|
for a fair pairing: a fresh sandbox session (`app/ui-sandbox.sh
|
||||||
|
spawn benchsession`, id `4d21d4a0d38f79fd`) with 30 identical sent
|
||||||
|
messages, each one heading/bold/italic/inline-code/link/list/fenced-
|
||||||
|
code paragraph, so both apps scroll the exact same bytes -- neither
|
||||||
|
of the two sessions quoted in this box's earlier passes (`8920378e
|
||||||
|
7167ebcd`, 40 msgs; `c76b71d017a54589`, 120 msgs) was reused, since
|
||||||
|
neither app had touched it. A sampler
|
||||||
|
(`date`/`/proc/loadavg`/`/proc/pressure/{cpu,io}`/top-5-by-CPU every
|
||||||
|
2s to `/tmp/iris-bench-sampler.log`) ran for the whole session,
|
||||||
|
started before either app was built, per the standing rule against
|
||||||
|
diagnosing a timing question from measurements taken after the
|
||||||
|
fact.
|
||||||
|
|
||||||
|
| app | build | GPU mode | frames | janky % | p50 | p90 | p99 | worst |
|
||||||
|
|---|---|---|---|---|---|---|---|---|
|
||||||
|
| Compose (in-app report) | debug | software | 1102 | 99.0% late | 33.8ms | 50.6ms | 79.5ms | -- |
|
||||||
|
| Compose (`dumpsys gfxinfo`) | debug | software | 1499 | 21.15% (95.66% legacy) | 32ms | 48ms | 150ms (99th) | -- |
|
||||||
|
| iris (`FrameReport`, run A) | **release** | software | 299 | 94.65% | 79.1ms | 98.6ms | 117.8ms | 212.6ms |
|
||||||
|
| iris (`FrameReport`, run B, repeat) | **release** | software | 233 | 94.42% | 109.3ms | 130.8ms | 147.1ms | 150.5ms |
|
||||||
|
|
||||||
|
Exact commands: Compose via `app/transcript-bench.sh` unmodified
|
||||||
|
(`open_session` then `copy_render_report` bracketing the standard
|
||||||
|
24-swipe/6-cycle loop, `dumpsys gfxinfo com.example.aiapp reset`
|
||||||
|
taken immediately before for the second row). iris via the same
|
||||||
|
24-swipe loop code -- extracted verbatim from
|
||||||
|
`transcript-bench.sh`'s `DO=""` .. `eval ui-trace record` block with
|
||||||
|
`sed`, not retyped, since `transcript-bench.sh` itself is Compose-
|
||||||
|
specific (opens by session title through the Compose app's own UI)
|
||||||
|
and could not be called directly -- bracketed by `ui-trace record
|
||||||
|
--do "tap 'Reset frame report'"` and `--do "tap 'Frame report'"`
|
||||||
|
(iris's own two named controls, I5's earlier "Update" section),
|
||||||
|
reading the result from `logcat`'s `iris frame report:` line.
|
||||||
|
|
||||||
|
**What each number counts, stated because the three are not the
|
||||||
|
same measurement.** Compose's in-app report times its own
|
||||||
|
Compose-internal phases (`total` = the full frame from Choreographer
|
||||||
|
callback to submit) and calls a frame "late" past a 16.7ms budget --
|
||||||
|
a stricter, self-reported definition. `dumpsys gfxinfo`'s "janky"
|
||||||
|
is Android's own HWUI/BLAST deadline-miss accounting, a different
|
||||||
|
threshold and a different frame population (it free-runs over
|
||||||
|
`Total frames rendered`, which includes frames from opening the
|
||||||
|
session and the report dialog, not only the swipe window -- hence
|
||||||
|
1499 vs. the in-app number's 1102). iris's `FrameReport` times
|
||||||
|
wall-clock from `render()`'s redraw start to after `queue.submit`+
|
||||||
|
`present()` -- i.e. iris's own render path only, nothing above the
|
||||||
|
GPU submit and nothing from Android's compositor -- confirmed
|
||||||
|
independently useless for iris via `dumpsys gfxinfo
|
||||||
|
dev.iris.android.demo`, which reported 1 total frame for the whole
|
||||||
|
run (unchanged from the earlier pass's finding: HWUI has no
|
||||||
|
visibility into a `wgpu`-drawn `SurfaceView`).
|
||||||
|
|
||||||
|
**Not comparable, stated plainly:**
|
||||||
|
- **Build profile differs by necessity, not choice.** Compose is
|
||||||
|
the **debug** variant (AGENTS.md's own bench-script requirement,
|
||||||
|
"the emulator scripts stay on the debug build"). iris is
|
||||||
|
**release** because I4's box already found the debug/dev profile
|
||||||
|
`SIGSEGV`s in this emulator's Vulkan loader the moment `wgpu`
|
||||||
|
creates a bind-group layout (`InstanceFlags::from_build_config()`
|
||||||
|
turns on debug object-labelling, which crashes against
|
||||||
|
`vulkan.ranchu.so`) -- there is no debug iris number to quote on
|
||||||
|
this rig. A release build is typically *faster* than debug, so
|
||||||
|
this asymmetry very likely understates how much worse than
|
||||||
|
Compose iris's own number would look built the same way Compose's
|
||||||
|
is, not the reverse.
|
||||||
|
- **The jank definitions and frame populations differ**, per the
|
||||||
|
paragraph above -- none of the three numbers is measuring the
|
||||||
|
same thing, so reading "94.65% > 21.15%" as "4x worse" is not
|
||||||
|
sound; only the general shape (iris's frames take longer, both by
|
||||||
|
its own accounting and by eye in the screenshots) transfers.
|
||||||
|
- **Both figures are emulator numbers under software rasterisation
|
||||||
|
(`EMU_GPU=software`/SwiftShader), not phone numbers**, per
|
||||||
|
AGENTS.md's and `this-machine-android`'s standing rule -- restated
|
||||||
|
because it applies doubly to iris's own number here: SwiftShader
|
||||||
|
is CPU-bound by design, and Compose's *own* in-app report shows a
|
||||||
|
14.6-22.2ms `swap` phase and a 20.8-33.9ms `gpu` phase alone (more
|
||||||
|
than the entire 16.7ms budget) under the same GPU mode, so a
|
||||||
|
software-rendering iris number well above 16.7ms is expected
|
||||||
|
going in and should not be read as an iris-specific defect
|
||||||
|
without a `-gpu host` pair to compare against.
|
||||||
|
|
||||||
|
**Where iris's time goes, from `FrameReport`/logcat -- not
|
||||||
|
optimised, per this task's own instruction, only described.** Two
|
||||||
|
things were checked because they were checkable without new
|
||||||
|
instrumentation: (1) **iris does not redraw while idle** --
|
||||||
|
`adb logcat -c` followed by a 3s settled wait produced *zero*
|
||||||
|
`iris::android::view: render()` lines, both before and after a
|
||||||
|
swipe; the render-per-frame spam only appears during and briefly
|
||||||
|
after a gesture (visible inertial settle), so there is no idle-
|
||||||
|
redraw tax to find here, unlike the composer-inset bug AGENTS.md
|
||||||
|
records for the Compose app. (2) **a swipe frame does not appear to
|
||||||
|
relayout the whole list** -- consecutive `render()` log lines during
|
||||||
|
a swipe show `active=88` falling to `83`, `78`, `73`, ... one small
|
||||||
|
step per frame, consistent with I3's virtualised list culling
|
||||||
|
widgets that scrolled out of the viewport rather than re-measuring
|
||||||
|
everything each frame (a full-list relayout would show `active`
|
||||||
|
constant at the total row count, not shrinking through it). Neither
|
||||||
|
observation isolates *where* the remaining ~80-150ms/frame actually
|
||||||
|
goes past those two rule-outs -- the leading remaining candidate is
|
||||||
|
the swapchain present/GPU path itself under SwiftShader's CPU
|
||||||
|
rasterisation, per the "not comparable" point above, but that was
|
||||||
|
not measured directly this pass (no per-phase breakdown inside
|
||||||
|
`FrameReport` the way Compose's report has `measure`/`place`/
|
||||||
|
`record`/`swap`/`gpu`).
|
||||||
|
|
||||||
|
**The dropout finding, corrected from earlier in this box: this
|
||||||
|
pass's own script bug, not a reproduction of the touch-delivery
|
||||||
|
candidate.** Of 3 planned attempts, the first 2 produced `iris frame
|
||||||
|
report: no frames recorded` -- but tracing it down found the cause
|
||||||
|
in this session's own tooling, not the emulator: the swipe loop was
|
||||||
|
extracted from `transcript-bench.sh` into a temporary wrapper script
|
||||||
|
that `cd`'d into `/tmp` before invoking `ui-trace`, and `ui-trace`/
|
||||||
|
`adb` here derive *which emulator to target* from the current
|
||||||
|
directory's basename (the per-checkout-AVD rule) -- from `/tmp` that
|
||||||
|
resolved to a nonexistent checkout named "tmp", `ui-trace` refused
|
||||||
|
immediately, and the wrapper's `set -eu` aborted the whole loop
|
||||||
|
before a single swipe was sent. Once the wrapper was fixed to run
|
||||||
|
from inside this checkout, the next **two** attempts (runs A and B
|
||||||
|
in the table above) both succeeded on the first try, each with a
|
||||||
|
confirmed screenshot-hash difference showing real scrolled content.
|
||||||
|
So this session did not reproduce the previously-documented
|
||||||
|
intermittent zero-touch phenomenon -- but two successes out of two
|
||||||
|
*valid* attempts is also too little evidence to say it is gone;
|
||||||
|
the earlier session's drops happened with a correctly-targeted
|
||||||
|
device, which is a different failure than the one found here.
|
||||||
|
**Sampler timeline**: `/tmp/iris-bench-sampler.log` shows
|
||||||
|
`/proc/loadavg` and the runnable-process count rising from an idle
|
||||||
|
baseline (~0.3-1.7 load, 0-4 running) to ~2.5-2.9 load and 11-23
|
||||||
|
running during the swipe window that produced run A -- consistent
|
||||||
|
with the standing candidate (SwiftShader's software rasterisation
|
||||||
|
loading the CPU during a gesture) but **not a confirmed cause**,
|
||||||
|
since both valid attempts succeeded despite the rise. Whether load
|
||||||
|
of that shape is what caused the *earlier* session's drops remains
|
||||||
|
unknown; this pass's sampler evidence neither confirms nor refutes
|
||||||
|
it, only shows the correlate is present under load without a
|
||||||
|
failure to correlate it to this time.
|
||||||
|
|
||||||
|
**Not attempted this pass**: the second `-gpu host` pair (time went
|
||||||
|
to the software-mode pair, the sampler, and diagnosing the dropout
|
||||||
|
above); a per-phase breakdown inside iris's own `FrameReport` the
|
||||||
|
way Compose's report has one; and syntax-highlighting/tappable-link/
|
||||||
|
accessibility-name gaps already named in "What remains" above,
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
**Verification for this update**: no Rust or Kotlin code changed
|
||||||
|
this pass (build/measurement only), so `cargo fmt`/`clippy`/`test`
|
||||||
|
were not re-run; `docs/DECISIONS.md`'s DEFERRED item is updated with
|
||||||
|
this table's headline numbers below rather than a decision made
|
||||||
|
here.
|
||||||
|
|
||||||
## For the next agent
|
## For the next agent
|
||||||
|
|
||||||
What to do when you pick this up, in order, so nothing here has to be
|
What to do when you pick this up, in order, so nothing here has to be
|
||||||
|
|||||||
Reference in new issue
Block a user