812 lines
49 KiB
Markdown
812 lines
49 KiB
Markdown
# ai-app bench
|
|
|
|
The two APKs for the phone benchmark gate (ai-app's `docs/RUST.md`, P0),
|
|
packaged for Dev Updater so they can be installed on a phone without a
|
|
build machine. Add this checkout as a project in Dev Updater (its
|
|
`.dev-updater.ron` names two APK components, `compose-bench` and
|
|
`iris-bench`, with no build step -- the APKs are committed under
|
|
`compose/` and `iris/`), then install each from its card. Both install
|
|
beside the real app under their own application ids and need no server,
|
|
no enrolment and no permissions.
|
|
|
|
**This is the publication repository, not the source repository.** The iris
|
|
APK is built from `~/repos/ai-app-2`'s `rustify` branch, copied to
|
|
`iris/build/outputs/apk/release/iris-bench-arm64.apk` here, then committed and
|
|
pushed on this repository's `main` branch. Dev Updater pulls this repository
|
|
and serves that committed APK; pushing `ai-app-2` by itself publishes nothing
|
|
to the benchmark card.
|
|
|
|
The rest of this file is the runbook that was delivered with the APKs.
|
|
|
|
**2026-09-09 (latest): growing layout settles in the frame that changed it.**
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `5ece49b`. This fixes the two
|
|
regressions found in the retained-transcript build: a newly streamed markdown
|
|
block no longer spends its first frame beside/overlapping the previous block,
|
|
and the multiline composer grows to its final viewport before it is masked, so
|
|
the first visible line and its padding are not clipped.
|
|
|
|
The fix is entirely in iris. A changed child's size was already measured up
|
|
through its ancestors; iris now lays that changed branch back down through the
|
|
final boxes in the same frame, and `Sized` no longer accepts a provisional box
|
|
for its descendants as final. The dedicated LazySpan regression and the real
|
|
phone-sized composer regression both fail without their respective fixes.
|
|
|
|
The retained move remains intact: the 401-event upload rig reports instance
|
|
uploads at **1.1% against a 1.1% floor** (p50 **1,488 bytes**) and an exact
|
|
11,569-slot arena for 11,569 live primitives. Streamed-frame CPU is p50 0.12ms,
|
|
p99 0.43ms, with no frame over 8.3ms in the layer-1 release profile.
|
|
|
|
**2026-09-09: pinned growth moves the retained transcript once.**
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `fffed42`. This is the
|
|
framework-level `LazySpan` change: when a streaming message grows and pushes
|
|
the transcript upward, retained rows keep stable local boxes and one shared
|
|
child-coordinate slot moves the subtree. There is no transcript-specific
|
|
rendering shortcut.
|
|
|
|
The layer-1 upload rig over 401 streamed events now reports instance uploads
|
|
at **2.9% against a 2.9% floor**, from 71.9% against 71.8%; median instance
|
|
upload fell from **176,496 bytes to 1,728 bytes**. Settled list movement is one
|
|
real list draw and one shared move-slot write. The framework and app suites,
|
|
the transcript edge/clamp tests, the arena rig, and a phone-shaped headless
|
|
fling replay all passed before this APK was published.
|
|
|
|
**2026-09-09 (later): the report itself was wrong in three places, and
|
|
two of them were mine from this morning.** Rebuilt from ai-app-2
|
|
`9bf714f`, iris APK only. Your run said "now THAT is smooth" and the
|
|
report did not deserve the credit it was taking:
|
|
|
|
- **`missed vsyncs` was counting the bench sitting idle**, not stutter.
|
|
276 for the sixteen 300ms rests between flings, 2410 for twelve hundred
|
|
50ms gaps between keystrokes, 821 for the 50ms between streamed events
|
|
-- each within a few percent of just multiplying it out. A gap only
|
|
means anything now if the frame before it had asked for another one.
|
|
- **`late` was counting the wait for the display as if it were cost.**
|
|
When the app is comfortably ahead, every frame is a little work then a
|
|
wait for its turn, so the total sits exactly on the budget and `late`
|
|
becomes a coin toss. It is judged on the work now.
|
|
- **Your display reported 60Hz for a run that drew 3405 frames in 33.1s.**
|
|
A phone that varies its refresh rate answers with whatever mode it is
|
|
in when asked, so every `late` figure in that report was judged against
|
|
twice the budget it should have been. The report now takes the larger
|
|
of what the display claims and what the run actually sustained, and
|
|
prints both when they disagree.
|
|
|
|
**And I misread your frame rate.** "103fps on a 120Hz screen" divided the
|
|
fling phase by its whole duration, rests included; excluding them both
|
|
runs sustained ~120.3fps. So the loop was never dropping frames -- the
|
|
thing that made it smooth is the clock the fling is sampled on, which
|
|
changes no frame count whatsoever. That is precisely why no number in
|
|
either report showed it, and why your eyes were the instrument that
|
|
mattered.
|
|
|
|
**What is worth reporting back now**: the `fling:` block's `build p50`
|
|
(iris's own work -- it was 0.4ms) and whether `missed vsyncs` is small.
|
|
The `acquire` figure beside it is the display pacing the app and wants to
|
|
be large.
|
|
|
|
**Streaming is the remaining cost**, and it is not the fold: folding an
|
|
arriving event is 0.35ms and applying it to the widget tree 0.41ms, while
|
|
the frame is 9.5ms on your phone. 401 streamed events move the item count
|
|
from 652 to 654, so nearly every one is a delta into the *same* row --
|
|
the cost is re-shaping one growing message on every delta. Fixing it
|
|
means changing how a row holds its shaped text, which I would rather
|
|
design with you than just do.
|
|
|
|
**2026-09-09: the fling. iris APK only** -- rebuilt from ai-app-2
|
|
`42d54ee`; the Compose one is unchanged from 2026-09-08.
|
|
|
|
You reported stuttering when flinging that is much harder to notice with
|
|
a finger on the scroll. Four things came out of it, and **two of them
|
|
were the report rather than the renderer** -- so read the new report
|
|
before reading the old numbers against it.
|
|
|
|
- **The swapchain wait was being counted as iris's CPU time.** The call
|
|
that hands back an image to draw into *blocks* until the compositor
|
|
frees one, and it was inside the span the report called `cpu_p50`. An
|
|
app comfortably ahead of the display spends most of every frame there,
|
|
so a perfectly healthy fling read as several milliseconds of iris being
|
|
slow. Each phase now says `build / acquire / submit` separately, and
|
|
only `build` is work.
|
|
- **Nothing could say a frame was never produced.** `late` counts frames
|
|
that *cost* more than a budget -- but a late frame still appears on the
|
|
next refresh, while a frame that never happens leaves the previous one
|
|
on screen twice, and that is what a stutter is. Every phase now carries
|
|
`missed vsyncs`. That is the number to watch.
|
|
- **iris asked for its next frame at the end of the frame callback**, and
|
|
Android schedules that for the next refresh *after the call* -- so any
|
|
frame whose work ran past the boundary registered too late and got the
|
|
refresh after it. One frame over budget silently cost a second one.
|
|
Your fling phase ran at 103fps on a 120Hz screen, which is the shape
|
|
that makes. It asks first now.
|
|
- **The fling was advanced on the wall clock, not on the vsync the
|
|
callback carries.** Frames are shown on an even cadence whichever clock
|
|
computed them, so sampling the coast curve at "whenever the callback got
|
|
to run" moves the transcript by an uneven distance every frame -- with
|
|
no frame late enough to appear in any percentile. **This is most likely
|
|
the thing you were seeing**, and it explains why a finger on the screen
|
|
doesn't have it: a drag's positions come from the finger's own
|
|
timestamps and never went through that clock.
|
|
|
|
Also `opt-level` for the Android build: it was tuned for size (`"s"`),
|
|
which costs a renderer its loop vectorisation. At `3`, iris's own
|
|
per-frame work over the same warm fling goes from p90 0.15ms / p99 0.42ms
|
|
to p90 0.09ms / p99 0.26ms. The APK grows 9.7 -> 11.5 MB; say if you'd
|
|
rather have the size.
|
|
|
|
**What is worth reporting back**: whether the fling *feels* smoother with
|
|
a finger, and the `fling:` block's frame count and `missed vsyncs`. If the
|
|
count is near 120 x its seconds and `missed` is small, the loop is fixed;
|
|
if `missed` is still large, the cause is elsewhere and the new split says
|
|
where. The CPU side is already known not to be it -- a warm fling is p99
|
|
0.26ms of layout, with only one frame in six laying anything out.
|
|
|
|
|
|
**2026-09-08: nothing on the transcript is unbounded any more,
|
|
and both APKs are new.** Rebuilt from ai-app-2 `afbc2ad`. This one has
|
|
things to look at, unlike the last.
|
|
|
|
**The edit-card lag you reported is fixed, and it was a framework bug.**
|
|
Not text layout: shaping and rasterising a 51,200-glyph block is 20ms, and
|
|
the frame that drew it took 1.37 seconds. Redrawing a widget frees every
|
|
primitive it owned and writes fresh ones, and finding each one's handle to
|
|
renumber was a scan of everything that widget drew -- so one redraw cost
|
|
O(its own glyph count squared). It is 29ms now, and linear. Expanding a
|
|
big card should feel immediate; if it still doesn't, that is a *different*
|
|
fault and worth saying so.
|
|
|
|
**Both apps now cap long things behind "Show all N lines".** Same rule and
|
|
the same numbers in both, so this comparison is still renderer against
|
|
renderer:
|
|
|
|
- a tool call's **input** -- 80 lines or 4 KiB. This is the one you asked
|
|
for; an `Edit`'s `old_string`/`new_string` used to arrive whole.
|
|
- a tool call's **output** -- same bound. iris already did this; the
|
|
Compose app didn't, and now does.
|
|
- a **message**, yours or the model's -- 200 lines or 16 KiB.
|
|
|
|
A reply still streaming is never capped, so watching one arrive is
|
|
unchanged. A message is cut between markdown blocks rather than through
|
|
one, so you should never see half a fence.
|
|
|
|
**Raw text no longer wraps in the Compose app** either -- a tool's
|
|
leftover input fields and its output pan sideways, the way the command
|
|
line already did. Both apps agree now.
|
|
|
|
Worth pressing: expand the biggest edit card you can find; press "Show
|
|
all" on a card and on a long message and check the transcript doesn't jump
|
|
under you; scroll a long output sideways.
|
|
|
|
**2026-09-08: scrolling is one mechanism, and this build is
|
|
mostly structure.** `iris-bench-arm64.apk` rebuilt from ai-app-2
|
|
`4fdabc3`, four commits on from the last one. **There is deliberately no
|
|
new feature here and little that should look different** -- it is the
|
|
scrolling rework you asked for after reading `docs/SCROLL.md`, plus the
|
|
two changes before it, so what this build is for is catching anything
|
|
that got *worse*.
|
|
|
|
- Everything a scroll position is made of now lives in one
|
|
`ScrollController` that the two scrolling widgets own, instead of a
|
|
protocol between a `Scroll` and the list inside it. The list is no
|
|
longer wrapped in a scroll area at all -- it is one widget doing its own
|
|
layout and its own scrolling -- and the `Widget` trait lost the three
|
|
scrolling methods that existed only to connect the two.
|
|
- A scroll delta's sign is now a screen direction (positive scrolls up or
|
|
left) rather than "toward earlier content", which pointed the opposite
|
|
way for a list laid out backwards. Nothing in this build lays one out
|
|
backwards yet, so this is a latent fix rather than something to see.
|
|
- The one behaviour that genuinely changed: a scroll delta is now applied
|
|
by the next frame's layout rather than the instant it arrives, because
|
|
the layout is the only thing that knows where the content ends. Input is
|
|
always followed by a frame, so this should be invisible -- if any
|
|
gesture feels a frame behind your finger, that is the change to suspect
|
|
and worth saying so.
|
|
- Earlier in the same run: one fling and one drag implementation for every
|
|
scroll area (a code fence, the composer and the transcript now share
|
|
exactly the same code), and the list's pin ("stay at the newest
|
|
message") is separate from which way it is laid out.
|
|
|
|
What to look for -- all of it is "does this still work", not "is this
|
|
new":
|
|
|
|
- Flick the transcript hard both ways: it should decelerate and stop
|
|
exactly on the first and last message, never past either.
|
|
- Put a finger down on a coasting transcript: it should stop dead under
|
|
your finger and then follow it.
|
|
- Flick a code block sideways while scrolling the transcript vertically
|
|
somewhere else -- the two should not interfere.
|
|
- Scroll the composer's text when a message is long enough to need it.
|
|
- While a reply is streaming, the view should stay stuck to the bottom;
|
|
scroll away and it should stop following, and coming back to the bottom
|
|
should re-stick.
|
|
- Selecting text with a long press should still work and should not pan.
|
|
|
|
|
|
**2026-09-08 (later still): the scroll lock, and the input box's clip.**
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `5e34dba`. Both are from
|
|
your report on the bench build, and both have a test that fails without
|
|
the change.
|
|
|
|
- **"If I try to scroll vertically while a horizontal scroll animation
|
|
is still active, it stays locked to the horizontal scroll."** Your
|
|
diagnosis was the right one: it was global state, and the fling had
|
|
nothing to do with it. A widget kept receiving presses for one frame
|
|
*after* the finger left it (the frame that exists so a hover can end),
|
|
and a press landing on something that is already coasting commits to a
|
|
pan immediately, with no slop -- so a code fence grabbed the whole
|
|
gesture from wherever on the screen you actually touched. Measured
|
|
before the fix: a finger put down 500px above a coasting fence and
|
|
dragged 160px down the screen moved the list by nothing at all. A
|
|
press now only reaches the widget it is actually on. What to try:
|
|
flick a code block sideways and, while it is still moving, scroll the
|
|
transcript up and down somewhere else -- the transcript should follow
|
|
your finger and the code block should carry on coasting on its own.
|
|
Putting a finger down *on* the coasting block still catches it,
|
|
whichever way you then drag, which is what Compose does.
|
|
- **"The message input box doesn't clip correctly."** It was clipped 12dp
|
|
inside its own edge, so a long message was sliced through the middle of
|
|
a line of text with a band of bare grey above the cut. The box itself
|
|
is the clip now -- the same rounded rect that draws the bar is what the
|
|
text is cut to, so text disappears under its edge. The padding still
|
|
holds the text off the edge at the end you are typing at. What to try:
|
|
type or paste more than six lines and scroll inside the box.
|
|
|
|
**2026-09-08 (late): the four defects from your second report.**
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `a2e5e58`. Everything here
|
|
comes from the report you sent, and each one has a test that fails
|
|
without the change -- but the phone is the only place three of them were
|
|
ever seen, so they want checking there.
|
|
|
|
- **"Leaving and reopening the app also randomly moved the vertical
|
|
scroll."** The system's own swipe up from the bottom edge to leave the
|
|
app was reaching iris as an ordinary flick *released at speed*, so the
|
|
transcript flung while the app was in the background and you came back
|
|
to a different place. A gesture the platform takes away is now a
|
|
cancel rather than a release: no tap, no selection, no fling derived
|
|
from it. What to try: scroll to somewhere you can recognise, swipe up
|
|
to leave, come back -- it should be where you left it.
|
|
- **"Flinging doesn't work in horizontal scroll areas."** It does now,
|
|
and not as something a caller opts into: every scroll area flings, on
|
|
either axis, through the same code the vertical list already used --
|
|
the same curve and the same release thresholds Compose uses. Two
|
|
things came with it that a sideways fence had never needed: the
|
|
display's real density (a hardcoded value made a one-second coast run
|
|
for forty-five), and catching a coasting fence with a finger, which
|
|
now stops it at that sample instead of after a slop distance. What to
|
|
try: flick a code block sideways, and put a finger down on one while
|
|
it coasts.
|
|
- **"Sometimes when I try to catch it while it's still moving it fails
|
|
to stop."** A row's text block drives the same gesture as the list
|
|
around it, and it was being told its own pan had been cancelled on the
|
|
frame that pan started -- so the drag ended the moment it began. A
|
|
widget that is itself driving the gesture now ignores that.
|
|
- **A row that changes height no longer paints its background at the old
|
|
one.** On the frame a row's measurement disagrees with the box it was
|
|
offered, it is drawn again at its true box in the same frame rather
|
|
than the next one -- so expanding or collapsing a tool card should not
|
|
flash a background that is the wrong size for one frame.
|
|
|
|
**2026-09-08 (evening): the crash on scrolling up, a devlog that can
|
|
show a panic, and icons from a font iris ships.** `iris-bench-arm64.apk`
|
|
rebuilt from ai-app-2 `9e301f3`.
|
|
|
|
- **The crash.** The bench built a texture per disclosure triangle -- one
|
|
per folded tool card, hundreds of copies of three pictures -- and the
|
|
path that rebuilds the renderer for a new GPU device forgot which slot
|
|
each was in, so a frame could ask for a texture that no longer existed
|
|
and the app aborted. It is one texture per shape now (three for the
|
|
whole screen), and a new device re-uploads what it had instead of
|
|
forgetting it, so the handles stay valid. On the emulator this was
|
|
reproducible on the *first frame*; there it now opens clean and takes
|
|
33 full-screen scrolls back through the fixture without complaint.
|
|
**Whether it was your crash is not confirmed** -- nothing recorded what
|
|
yours was, which is the other half of this build.
|
|
- **The Runtime tab will show a panic now.** It only ever had one line
|
|
because, after a crash, Dev Updater's query starts the app for the
|
|
*provider alone* -- no screen, so the code that replays the previous
|
|
run's crash file never ran. The provider does that itself now, and the
|
|
crash file carries the last 80 log lines from the run that died as well
|
|
as the panic, replayed in order: what the app was doing, then what
|
|
killed it, then this run. So if it still crashes, open Dev Updater's
|
|
Runtime tab afterwards and send what is there.
|
|
- **The disclosure triangles come from a font now.** You were right that
|
|
this should have been the icon font: the Compose app ships its own Nerd
|
|
Fonts subset and iris shipped none, so its mark was a bare Unicode
|
|
codepoint your phone had no face for. iris has its own subset now (992
|
|
bytes, three Material Design glyphs, same Mono face as the Compose
|
|
app's), the drawn triangle is deleted, and a missing codepoint now
|
|
fails a test rather than drawing nothing. If a mark is the wrong size
|
|
or sits wrong beside the tool name, say so -- it is a font size now, so
|
|
it is one number.
|
|
- Side effect worth knowing: switching away from the app and back no
|
|
longer re-rasterises every glyph on screen.
|
|
|
|
**2026-09-08: catching a moving list, and rounded code fences that clip
|
|
on the curve.** `iris-bench-arm64.apk` rebuilt from ai-app-2 `38bf630`.
|
|
Two things from your last report, and both want checking on the phone
|
|
because neither is confirmed there yet:
|
|
|
|
- **"Sometimes when I try to catch it while it's still moving
|
|
(particularly if I drag) then it fails to stop & snap to where finger
|
|
is."** A finger put down on a moving list now stops the fling *at that
|
|
sample* and drags from it with no slop wait, which is what Compose
|
|
does. A catch you put down and lift without moving is no longer
|
|
treated as a tap. What to try: flick hard, then put a finger down
|
|
mid-flight and drag slowly — the content should be pinned to your
|
|
finger from the first movement, not after a jump.
|
|
- **Code blocks clip on their rounded corners.** A mask carries a shape
|
|
now rather than a rectangle, so a code fence's content is cut on the
|
|
panel's own curve instead of an inner square, and the corners of
|
|
nested clips multiply their alpha rather than fighting. Touch obeys
|
|
the same shape: a corner rounded away is not pressable. What to try:
|
|
scroll a code block sideways and look at its four corners, and try
|
|
pressing just outside one.
|
|
|
|
Also in this build: the app no longer refuses to start on a device whose
|
|
only usable adapter is a GLES one (it falls back and says so in the log
|
|
rather than aborting), and `primitives=` in a frame report no longer
|
|
counts clip shapes that are never drawn.
|
|
|
|
If something is wrong, the **Copy report** button always copies now —
|
|
the log tail comes with it, and Dev Updater's **Runtime** tab on this
|
|
component reads the app's log directly off the phone.
|
|
|
|
|
|
**2026-09-06: composing text + caret, composer layout, text survives app
|
|
switch.** `iris-bench-arm64.apk` rebuilt on top of the fling/stream/type/
|
|
keyboard bench v2 above (same commit range, merged). Fixes from Iris's
|
|
phone report on the previous build: Gboard's composing keystrokes now sync
|
|
back to the app (`InputMethodManager.updateSelection`, previously never
|
|
called, which is why typing looked stuck until a space); swiping over the
|
|
composer bar no longer opens the keyboard (only a completed tap does,
|
|
confirmed on the emulator); and text no longer disappears after leaving
|
|
and returning to the app (a genuinely new renderer now clears the CPU-side
|
|
glyph cache instead of leaving it pointed at a destroyed GPU device). The
|
|
composer itself was also rebuilt as one widget with a height cap and
|
|
insets-aware bottom padding. **Not fixed**: composed/typed text still does
|
|
not become visible on screen at all, a separate, deeper bug found while
|
|
verifying the above -- ruled out as a widget-layout bug (a new unit test
|
|
proves the region math is correct), still open. See ai-app-2's
|
|
`docs/RUST.md`, P0 box, for the full account, what was verified on the
|
|
emulator, and what still needs a real device or Vulkan to isolate.
|
|
|
|
**2026-09-06: bench v2 (fling/stream/type/keyboard).** `compose-bench-arm64.apk`
|
|
rebuilt with the four-phase benchmark Iris asked for after using v1 on her
|
|
phone -- a real fling (12,000px/s through the list's own `FlingBehavior`,
|
|
not the old tween-based swipe, so it travels much further per gesture),
|
|
the existing 400-event/20s stream, a type phase (600 fixed characters
|
|
typed into the real composer then deleted, to exercise wrapping and the
|
|
transcript being pushed upward), and a keyboard phase (five show/hide
|
|
cycles). The report gains a `per phase:` block (frames/late/percentiles/
|
|
worst/duration per phase) ahead of the existing whole-run sections, and
|
|
`bench:` gains the fling phase's travel, the typed character count, and
|
|
how many of the ten keyboard toggles were confirmed by the platform. Full
|
|
spec and the emulator smoke run are in ai-app-2's `docs/RUST.md`, P0 box,
|
|
"Benchmark v2 (2026-09-06)". Same steps below still apply -- "Run
|
|
benchmark" is unchanged in name and location.
|
|
|
|
---
|
|
|
|
# P0 benchmark APKs
|
|
|
|
Two arm64 builds, asked for in docs/RUST.md's P0 box (the phone benchmark gate Iris asked for
|
|
2026-09-05, "before P1 I'd like to see benchmarks & also maybe stress test on my own phone"). Each
|
|
opens straight onto the same synthetic fixture transcript with no server, runs the same scripted
|
|
scroll-and-stream benchmark, and produces a text report to paste back. **Install both, run both,
|
|
paste both reports back** -- the gate is a comparison, not either number alone.
|
|
|
|
## Compose (`compose-bench-arm64.apk`)
|
|
|
|
1. Install it (it has its own application id, `com.example.aiapp.bench`, and its own label "AI
|
|
Sessions bench" -- it installs beside a real enrolled "AI Sessions" without touching it).
|
|
2. Open it. It goes straight to a session screen holding the fixture transcript -- no enrollment,
|
|
no permission prompts.
|
|
3. Tap the gear icon top-right ("Session settings").
|
|
4. Tap "Run benchmark". It scrolls the transcript (the same 24-swipe loop
|
|
`app/transcript-bench.sh` drives on a phone from a computer), then streams 400 more fixture
|
|
events in over 20 seconds pinned to the newest end (the same shape `app/stream-bench.sh`
|
|
measures), then copies a report to the clipboard and shows a toast.
|
|
5. Paste the clipboard back here (or in whatever you're pasting reports into). It is plain text
|
|
with units on every number: frame counts and percentiles, the draw-phase accounting, and a
|
|
`bench:` section this build added -- process CPU time, peak RSS, and battery current sampled
|
|
once a second (says "unavailable" rather than a fabricated number where the phone can't answer,
|
|
per this project's rule against showing an inferred value as a measured one).
|
|
6. If you want to run it again, "Run benchmark" can be pressed more than once -- each press resets
|
|
the counters first, so the report only covers that run's own scroll and stream.
|
|
|
|
Built from `app/androidApp`'s `bench` build type; see `app/build-apk.sh bench` and
|
|
`app/bench-fixture/README.md` for how the fixture it opens was generated (deterministic, checked
|
|
into the repo, never a real transcript).
|
|
|
|
## iris (`iris-bench-arm64.apk`)
|
|
|
|
1. Install it -- own application id, `dev.iris.android.demo.bench` (an `applicationIdSuffix` on
|
|
the same `dev.iris.android.demo` the plain iris tabs demo uses, so it installs beside that one
|
|
too), needs no permissions beyond `INTERNET` (unused here -- inherited from the same manifest
|
|
`transcript-screen` needs, harmless for a build that talks to nothing).
|
|
2. Open it. Same fixture as the Compose build (the identical checked-in
|
|
`app/bench-fixture/assets/transcript.jsonl`), opened with no server through `client-core`'s real
|
|
`fold_page` -- there is no enrollment step here at all, iris's shell has none yet.
|
|
3. Tap "Run benchmark" (the whole screen is just two buttons above the transcript and a report
|
|
area below it -- no settings dialog to find it in). It runs the identical scripted loop: the
|
|
same 24-swipe/6-cycle scroll (900px over 200ms, 500ms apart, animated in ~60Hz steps rather than
|
|
jumped so real frames render along the way), then the same 400-event/20s streaming phase pinned
|
|
to the newest end, through `fold_event` -- the same fold path a live SSE reply uses.
|
|
4. The report appears in the text area under the buttons (it is a selectable field, so it can be
|
|
copied by hand too) and is logged under logcat's `iris-android-app` tag on the line starting
|
|
`iris bench report:`. Tap "Copy report" to put it on the clipboard through the shell's own
|
|
`ClipboardManager` (no toast -- watch logcat or the on-screen text for confirmation it worked).
|
|
5. Paste it back. Same units, most lines the same shape as Compose's -- frame count, janky
|
|
percentage, p50/p90/p99/worst -- plus iris's own CPU/GPU split (`cpu_p50`/`gpu_wait_p50`, from
|
|
`FrameReport::record_split`) where Compose's report has its draw-phase accounting instead, and a
|
|
`bench:`-shaped tail with the same three added fields: process CPU time over the run
|
|
(`getrusage(RUSAGE_SELF)`), peak RSS (`/proc/self/status`'s `VmHWM`), and battery current sampled
|
|
once a second through `BatteryManager.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW)` -- "no
|
|
frames recorded" / "unavailable" rather than a fabricated number wherever the phone can't answer
|
|
one, same rule Compose's report follows.
|
|
6. "Run benchmark" can be pressed again; it resets `FrameReport` first, so a second run's report
|
|
covers only that run.
|
|
|
|
Built with `iris/android-app/build-apk.sh release --abi arm64-v8a` (wraps `cargo ndk -t arm64-v8a
|
|
-P 26 -o app/src/main/jniLibs/ build --release --features "transcript-screen bench"` plus `gradle
|
|
:app:assembleRelease`, signed with the same `~/.config/ai-app/release.jks` `app/build-apk.sh`
|
|
generates, and verifies the result with `aapt2`/`apksigner`). **No longer built with `force-gles`
|
|
as of the 2026-09-06 rebuild below** -- see that entry for why it was there and why it had to come
|
|
out for a phone build specifically.
|
|
|
|
**2026-09-06, commit `46d3a6f`**: rebuilt after `transcript_ui::TranscriptScreen::apply` replaced
|
|
the full-rebuild-per-event streaming path in all three iris clients (docs/RUST.md's P0 box has the
|
|
before/after numbers) -- this is the build to use if comparing against an iris APK from before that
|
|
commit.
|
|
|
|
**2026-09-06, second rebuild, ai-app-2 commit `46246ea`**: this build aborted on Iris's
|
|
phone (a Pixel, GrapheneOS) in `AndroidRenderer::new`, on the very first `surface_changed`, with
|
|
only `wgpu error: Validation Error` surviving into the crash report before Android truncated it.
|
|
Two things changed:
|
|
|
|
1. **A renderer-creation failure no longer aborts the process.** `iris_core::UiRenderNode::new`
|
|
now runs its bind-group-layout/pipeline creation inside wgpu error scopes and returns
|
|
`Result<Self, String>` instead of letting wgpu's default handler panic; the Android backend
|
|
turns a failure into the adapter's identity, the exact limits and downlevel flags bind-group
|
|
layouts validate against, and wgpu's own "Caused by" chain, logged as one line under the
|
|
`iris-android-app` logcat tag and shown on screen as plain, selectable, scrollable text (a
|
|
`TextView` swapped in for the whole activity) saying to copy it and send it back. If this build
|
|
still fails on the phone, **that screen is what to screenshot or copy** -- there is no more
|
|
silent abort to chase through a truncated crash report.
|
|
2. **This build no longer forces the GLES backend.** Every earlier `iris-bench-arm64.apk`
|
|
(including the one above) was built with `--features "... force-gles ..."`, a flag that exists
|
|
only to force the *emulator* off its default software Vulkan and onto GLES for one specific
|
|
frame-time measurement (RUST.md's I5) -- its own doc in `iris/Cargo.toml` never mentions real
|
|
hardware. `build-apk.sh`'s default feature list carried it into every arm64 build regardless,
|
|
so the APK actually delivered to a phone was locked to GLES rather than the phone's own Vulkan
|
|
driver. That is the named hypothesis for the crash (docs/RUST.md's P0 box has the full audit):
|
|
GLES support for a storage buffer bound in the *vertex* stage (`move_offsets`, `masks_layout`)
|
|
depends on the driver reporting `GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS > 0`, which real Vulkan
|
|
grants unconditionally but a phone's GLES path is not guaranteed to -- and RUST.md's own
|
|
SwiftShader finding already flagged GLES-on-Android as the fragile backend for this exact
|
|
shader. This build uses the default backend (Vulkan on a real device) instead.
|
|
|
|
If this rebuild still crashes, the on-screen report from point 1 names the real cause directly;
|
|
paste it back rather than guessing further from a truncated log.
|
|
|
|
## 2026-09-06, later: bundled fonts, content-scale fix, Diagnostics control
|
|
|
|
Iris's first real-phone report on the previous rebuild (no crash) found four
|
|
defects the emulator never showed: every glyph disappearing on the first tap
|
|
or scroll (rectangles stay drawn -- not root-caused this pass, but a phone
|
|
report from this build's new Diagnostics page would help), bold words
|
|
rendering as blank gaps (fixed -- bundled Noto Sans/Noto Sans Mono, static
|
|
per-style faces, ahead of the platform's own fonts), text far too small
|
|
(fixed -- iris had no device-pixel-ratio handling on either platform before
|
|
this; density now divides window size, touch coordinates and the shader's
|
|
window uniform down to logical units), and the top buttons sitting under the
|
|
status bar (fixed -- a new `AndroidAppState::on_insets_changed` hook, unused
|
|
until now).
|
|
|
|
This build also adds a third **Diagnostics** button next to Run/Copy,
|
|
filling the report area with adapter identity, font resolution, the atlas's
|
|
view count, every wgpu error seen since surface creation, and the frame
|
|
report -- "copy this and send it to Iris" via the existing Copy button.
|
|
|
|
Full account, including what's still unverified on a real phone, in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, later still: keyboard-wipe fix, a density unit for crisp text, header background
|
|
|
|
Iris's report on the previous rebuild, with screenshots: text now the
|
|
right size but **blurry**; opening the keyboard still **wipes every
|
|
glyph** (rectangles stay, only text disappears); the **header buttons
|
|
have nothing behind them and overlap the transcript text**.
|
|
|
|
- **Keyboard wipe**: `surface_changed` fires on every surface resize, not
|
|
only a genuinely new surface -- showing the keyboard under
|
|
`adjustResize` is exactly such a resize. It was rebuilding the whole
|
|
renderer (a fresh, empty glyph atlas) every time, while the CPU-side
|
|
glyph cache kept coordinates into the *old* atlas. Fixed: reuse the
|
|
existing renderer's device/atlas/buffers and only reconfigure the
|
|
surface when one is already live. Confirmed on this checkout's own
|
|
emulator two ways (a forced display resize and an actual soft-keyboard
|
|
open) -- text stayed on screen both times.
|
|
- **Blur**: the previous fix's global "logical size" stretch (window
|
|
divided by density, then displayed stretched back up) rasterised each
|
|
glyph small and displayed it bigger than it had texels for. Fixed with
|
|
the density-independent length unit Iris asked for the same day (a new
|
|
`dp` alongside the existing physical-pixel and relative lengths,
|
|
resolved against the display's density at layout time) -- text now
|
|
rasterises at the display's real physical resolution.
|
|
- **Header**: only each button's own coloured rect painted anything, so
|
|
gaps between/around them showed the black clear colour one layer back,
|
|
and the row's reserved height did not match the (now density-correct)
|
|
transcript below it. Fixed with an opaque panel behind the whole row
|
|
and every header size moved onto the new `dp` unit.
|
|
- **New**: the bench build now auto-captures a diagnostics report ~500ms
|
|
after the keyboard opens (logged, copied to the clipboard, and shown in
|
|
a plain overlay with Copy/Close over the running app) -- so a report
|
|
can come back even if a keyboard-triggered regression is still
|
|
happening.
|
|
|
|
**Not fully verified.** This build has not been run on Iris's actual
|
|
phone. It was verified end to end on this checkout's own emulator
|
|
(`run-bench.sh`, no crash, 24/24 swipes, 400/400 streamed events;
|
|
before/after screenshots for the two keyboard-resize tests above). While
|
|
verifying, a **separate, not-yet-fixed issue turned up**: after a
|
|
keyboard-triggered resize, the header row appeared to render a second
|
|
time, out of place, inside the transcript area, and a tap meant for the
|
|
message field below landed on a header button instead (a benchmark run
|
|
started unexpectedly). Not root-caused, and not confirmed to be caused by
|
|
this pass's changes rather than something pre-existing -- worth watching
|
|
for on the phone and reporting back if seen. Full account in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, later still: Benchmark v2 (fling/type/keyboard), the header-duplicate finding, the ime-inset finding
|
|
|
|
**New**: "Run benchmark" now runs the same four-phase script the Compose
|
|
build's v2 does -- fling (8 flings out + 8 back at 12,000px/s through
|
|
`List`'s own new fling, matching Android's real deceleration curve),
|
|
stream (unchanged), type (the same 600-character string, one character
|
|
per 50ms into the real composer, then deleted), and keyboard (five
|
|
show/hide cycles). The report gained a `per phase:` block (frames, late
|
|
%, p50/p90/p99, worst per phase) and the whole-run `frames:` line now
|
|
reads the display's real refresh rate instead of assuming 60Hz.
|
|
|
|
**The header-duplicate bug from the previous entry: still not fixed.**
|
|
Reproduced reliably this pass (tap the composer field, screenshot after
|
|
the keyboard opens -- the three-button row appears twice, once at its
|
|
real position and once inside the transcript). One real, targeted fix
|
|
was tried and **ruled out**: skipping the header rebuild when the
|
|
status-bar inset hasn't actually changed (since a keyboard toggle also
|
|
re-fires this callback for an unrelated reason) -- the duplicate still
|
|
reproduced identically after that fix, so repeated rebuilding is not the
|
|
cause. Still unexplained; needs either live instrumentation of the
|
|
layout engine's two-phase span placement or a person with the phone.
|
|
|
|
**Found, and partly explains why the keyboard phase and the
|
|
keyboard-open auto-diagnostics both read "not confirmed" on every
|
|
run so far**: this app's `AndroidManifest.xml` uses
|
|
`windowSoftInputMode="adjustResize"` (needed so the keyboard resizes the
|
|
window instead of panning it off screen), and under `adjustResize`
|
|
`WindowInsets.Type.ime()`'s own inset *amount* is defined to read zero --
|
|
the window already shrank to avoid the overlap that inset would
|
|
otherwise report. Fixed the app to read `WindowInsets.isVisible(ime())`
|
|
(a boolean, unaffected by resize-vs-pan) instead of the numeric inset --
|
|
correct on its own terms, but on this emulator the insets listener still
|
|
never re-fires at all once the keyboard opens (a separate, deeper
|
|
platform behavior tied to this activity not being edge-to-edge, not
|
|
fixed this pass -- changing that is a bigger, riskier window-behavior
|
|
change than the time available justified). So the keyboard phase's "0
|
|
confirmed" and the auto-diagnostics not firing are both still open,
|
|
now for a specific, named reason rather than an unknown one.
|
|
|
|
Full account, including what was tried and ruled out, in
|
|
`docs/RUST.md`'s P0 box in the `ai-app-2` repo (`rustify` branch).
|
|
|
|
## 2026-09-06, evening: typing, launch layout, fling, per-block streaming, doubled rows
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 commit `20303e0` (arm64 Vulkan release,
|
|
`iris/android-app/build-apk.sh release --abi arm64-v8a --features "transcript-screen bench"`).
|
|
Everything since the 02:07 build, in one entry -- two intermediate builds went to the wrong
|
|
folder and never reached this repo:
|
|
|
|
- **Launch layout**: the black third below the composer was the bench shell's own empty
|
|
report pane taking a third of the screen, not an inset bug. Sized to its content now.
|
|
- **Typing**: tapping the empty composer focused it with no caret, so every keystroke was
|
|
dropped. Fixed, with a regression test. Text should appear as you type.
|
|
- **Fling and swipe from the composer**: dragging is now iris's own `DragGesture` with pointer
|
|
capture. A fast swipe keeps moving after release; a pan starting on the grey bar is taken by
|
|
the list from the frame it commits.
|
|
- **Doubled rows** (the `Compacted:` row, and the earlier doubled header): a widget redrawn
|
|
through its ancestor while marked dirty never freed its previous primitives, so they were
|
|
drawn every frame for the life of the process. Fixed; a debug-build assertion now checks
|
|
every frame that no primitive outlives its widget.
|
|
- **Streaming re-lays out only the block the delta lands in.** A message row is a column of
|
|
one text widget per markdown block; a streamed delta replaces the last block only (one text
|
|
shape per delta into a 100-paragraph reply, by counter). Emulator stream-phase p99 went
|
|
343ms -> 137ms. **The stream phase on your phone is the number to look at** (it was p50
|
|
18.2ms vs Compose's 13.4ms before).
|
|
- **Selection is per block**: a drag selects within and across blocks; copy joins them. Whether
|
|
a block should be the selection unit is yours to judge (`docs/DECISIONS.md`, 2026-09-06).
|
|
- **The composer scrolls under a finger** when it overflows its six-line cap.
|
|
- Also fixed: every widget's tap target sat short of its drawing by its last move (from
|
|
launch); stale mask slots after a keyboard resize; a targeted-redraw abort on masked
|
|
widgets; the full-screen diagnostics overlay on every keyboard open is gone (logged only).
|
|
- **App-switch text loss** did not reproduce on the emulator, so this build logs one line per
|
|
surface event with glyph counts. If text still vanishes on returning to the app, please send
|
|
`adb logcat | grep -i iris` from around the return; `already_live=true` on the way back in
|
|
names the cause outright.
|
|
|
|
Not in this build: markdown block styling (headings, highlighted fences, lists, tables, links)
|
|
and tool-call cards, which landed on `rustify` after it -- next build.
|
|
|
|
## 2026-09-07: the keyboard reopens, the composer moves for the IME, and a fling actually flings
|
|
|
|
From `ai-app-2` commit `ba0f2ea` on `rustify` (`iris-bench-arm64.apk`, arm64 release,
|
|
minSdk is 29 now). This build answers all four items of your 22:16 report.
|
|
|
|
- **"I can't reopen keyboard by tapping on message box."** Fixed. Dismissing the keyboard
|
|
leaves the field focused, and the only code path that asked for the keyboard was the one
|
|
that ran when a field *became* focused, so it never ran again. A tap on an already-focused
|
|
field asks for it now, exactly as Android's own `EditText` does. Checked on the emulator
|
|
both ways: with the fix the second tap opens it, without it the second tap does nothing.
|
|
Swiping over the composer still summons nothing, which is the thing this could have broken.
|
|
- **"Message box does not push up the scroll area."** Fixed. The keyboard's *height* was being
|
|
sent across to Rust as the boolean 1, so nothing had a number to pad by. Height and
|
|
visibility are two separate values now. On the emulator the composer rises by exactly the
|
|
keyboard's height and the transcript shrinks to match.
|
|
- **"Fling still doesn't work."** Three separate faults, all fixed, and **this is the one to
|
|
test hardest** because the emulator cannot reproduce your phone's input timing.
|
|
1. A fast flick at 120Hz arrives as one or two events with the in-between positions batched
|
|
inside them, and we were reading only the last position -- so the speed came out as zero.
|
|
Every batched sample is replayed now, each with its own timestamp.
|
|
2. Nothing in iris advanced a fling between input events at all. The benchmark drove its own
|
|
fling loop, which is why the bench "flung" and a finger never did. Widgets can animate now.
|
|
3. Once flings finally moved, one lasted 45 seconds: two constants were wrong (a hardcoded
|
|
display density, and the scroll friction used where Android uses its own 0.84 tuning
|
|
number -- a factor of 56 inside an exponential). A flick now coasts for the time Android's
|
|
own formula says: 1.6s for a hard flick, 0.6s for a gentle one.
|
|
|
|
**If it still does not fling on your phone**, the one line that settles it is
|
|
`adb logcat | grep "iris drag release"` -- please send it. `samples=1` or `span=0.0ms` means
|
|
the batched samples are not reaching us on your device; a sensible span with `v=` in the
|
|
thousands and `outcome=Released(Some(...))` means the gesture is measured correctly and
|
|
whatever is wrong is after that point. `outcome=Tapped` means the flick never counted as a
|
|
drag at all.
|
|
- **"The textures are getting cooked after leaving the app and resuming."** Fixed in
|
|
`ba2afba`, with a headless test, but **not confirmed on a device**: no emulator here has a
|
|
Vulkan adapter and the GLES path may not destroy the surface at all, so this one needs your
|
|
phone. The cause was one cache deeper than the last build's fix reached -- each text widget
|
|
kept its own laid-out glyphs with the *old* atlas's coordinates and re-submitted them
|
|
verbatim, which is why only text drawn after the resume looked right. The atlas carries a
|
|
generation now and a cleared atlas invalidates every cached layout at once.
|
|
|
|
Also in this build, both found while checking the above: a tap on the composer aborted every
|
|
debug build (a fixed bound on how deep a widget can nest was 16 and the composer is 17 deep --
|
|
in a release build like this one it did not crash, it silently drew and hit-tested that part of
|
|
the tree in the wrong place), and the app now requires Android 10 or newer, because the
|
|
per-sample touch timestamps the fling fix needs are API 29.
|
|
|
|
Still not fixed, and unrelated to any of the above: the composer bar's grey background is not
|
|
drawn on this build, so the transcript shows through behind the message field.
|
|
|
|
## 2026-09-07, later: the fling curve was a straight line, and the keyboard was one build setting
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `rustify` commit `4274b8b`.
|
|
This is the build for your three lines on the last one.
|
|
|
|
**"It seems to just be linear velocity with an abrupt stop."** It was
|
|
exactly that, and not approximately -- the curve iris used to shape a
|
|
fling returned a straight line for every input. Android's own deceleration
|
|
curve is built by a loop that solves one cubic and samples a *different*
|
|
one; iris had both halves solving and sampling the same one, which made the
|
|
two tables it builds identical, and the lookup that reads one against the
|
|
other then cancels out to "distance is proportional to time". So a flick
|
|
coasted at its release speed for the whole (correctly computed) duration
|
|
and then stopped dead at the end of it.
|
|
|
|
It is ported exactly now, from Android's `OverScroller.java` and from
|
|
Compose's own copy of the same curve, which agree line for line -- so a
|
|
fling here should travel and slow the way every other Android scroll view
|
|
does. On the emulator a released 3750px/s now decelerates
|
|
3746 -> 2624 -> 1834 -> 1144 -> 752 -> 449 -> 243 -> 83px/s across 32
|
|
frames, where before it would have held 3750 for all of them. **What to
|
|
look for**: a flick should visibly slow before it stops, and a longer flick
|
|
should slow over a longer distance. Two things that also should hold, both
|
|
checked here: a flick into the top or bottom of the transcript stops there
|
|
without bouncing, and putting a finger down during a fling stops it dead.
|
|
|
|
Worth saying because it is the reason this took two builds: every test the
|
|
fling code had compared it against itself -- is it monotonic, is the sign
|
|
right, does it add up to the total -- and **all of them pass on a straight
|
|
line**. The expected numbers are now generated by a separate transcription
|
|
of Android's source that does not share a line of code with iris.
|
|
|
|
**"The keyboard raising up does not push things upwards."** This one was a
|
|
single line of the bench app's build file: it declared it targeted Android
|
|
14, while the real app (the Compose one, whose keyboard does push its
|
|
transcript up on your phone) declares 17. Below the Android 15 target line
|
|
a window keeps the old behaviour, where the system shrinks the window for
|
|
the keyboard and therefore reports the keyboard's height to the app as
|
|
zero -- nothing left to push up. The emulator here is a version where the
|
|
old opt-out still works, which is why it pushed up in every test run and
|
|
not on your phone.
|
|
|
|
**This one is a reading, not a measurement** -- there is no Android 17
|
|
device I can reach. So the other half of the change is making your phone
|
|
able to answer it without a log. **Press `Diagnostics` with the keyboard
|
|
open and screenshot the line beginning `insets:`.** It looks like
|
|
|
|
insets: dispatches=27 left=0 top=142 right=0 bottom=63 ime_bottom=0 ime_visible=false
|
|
|
|
- `ime_bottom` in the hundreds, and the message box has risen: fixed.
|
|
- `dispatches` counting up but `ime_bottom=0`: my reading was wrong and the
|
|
window is still being resized. That is the useful failure.
|
|
- `dispatches=0`: the system is not telling the app about insets at all,
|
|
which is a third thing again and would say so in words instead of
|
|
numbers.
|
|
|
|
The keyboard's height also arrives over a second path now (the animation
|
|
callback), so the push-up follows the keyboard up rather than jumping when
|
|
it lands.
|
|
|
|
**"The resume glyph corruption is fixed."** Thank you -- closed on your
|
|
evidence. That was the one nothing here could ever have confirmed: no
|
|
emulator on this machine has a Vulkan adapter, and the software path may
|
|
not destroy the surface at all, so the state you photographed was not
|
|
reproducible here.
|
|
|
|
Still not fixed, and still unrelated: the composer bar's grey background is
|
|
not drawn on this build, so the transcript shows through behind the message
|
|
field.
|
|
|
|
## 2026-09-07, evening: clamped scrolling, a faster flick start, platform fonts, enrollment, and a runtime log Dev Updater can read
|
|
|
|
`iris-bench-arm64.apk` rebuilt from ai-app-2 `rustify` commit `92985ba`,
|
|
against the last delivery (`b47eb73`, the fling-curve + keyboard-targetSdk
|
|
build). APK **9,639,224 bytes**, `libmain.so` **7,506,448 bytes** (arm64-v8a
|
|
only) -- both smaller than that build, mostly from replacing the bundled
|
|
Noto fonts with the platform's own (Roboto for body text, Droid Sans Mono
|
|
for code) and a further release-profile tuning pass; docs/RUST.md has the
|
|
full size table.
|
|
|
|
What changed:
|
|
|
|
- The list is now clipped to its own box and rows are drawn at both edges --
|
|
nothing scrolls up behind the header, and there is no blank band at
|
|
either end.
|
|
- Scrolling is clamped at both ends of the transcript, matching the fling
|
|
fix from the last build: you cannot drag or fling past the top or the
|
|
bottom.
|
|
- A released flick now starts at the speed your finger was actually moving
|
|
at, using the same least-squares velocity estimator Compose itself uses,
|
|
rather than a slower approximation -- a flick should feel like it starts
|
|
fast and decelerates, not like it ramps up.
|
|
- The clock that timestamps each touch sample was misdating batched input,
|
|
which fed wrong numbers into that velocity estimate; it now dates them
|
|
correctly.
|
|
- Code blocks render in a real monospace font and body text in Roboto --
|
|
both platform fonts now, not the bundled Noto this build removes.
|
|
- The app enrols itself from the `aiapp://enroll` link -- Dev Updater's
|
|
Enroll button on this APK's component opens it directly. Diagnostics
|
|
shows either `enrolled: host:port` or `not enrolled`.
|
|
- The app exposes its own log to Dev Updater: APK component -> log button
|
|
-> Runtime tab. This needs the updated Dev Updater build on the host to
|
|
show anything.
|
|
- A "Trace" switch in the bench header turns on a line per input and per
|
|
frame in that log, for when a report alone isn't enough to say what
|
|
happened.
|
|
- Several of the invariants this code relies on internally are now hard
|
|
assertions in this release build, rather than silently-wrong behaviour if
|
|
one is ever violated.
|
|
|
|
What to look for:
|
|
|
|
- The header shows nothing behind it, at either edge of a scroll.
|
|
- You cannot scroll past the top or the bottom of the transcript.
|
|
- A flick starts at roughly the speed of your finger and visibly
|
|
decelerates, rather than ramping up or holding a constant speed.
|
|
- Code blocks are monospace; body text is not.
|
|
- Opening the keyboard pushes the composer up. If it doesn't, screenshot
|
|
Diagnostics' `insets:` line as in the last build's report.
|
|
- Dev Updater's Runtime tab (APK component -> log button) shows this app's
|
|
own lines, once the host's Dev Updater is updated.
|
|
- With Trace on, do a few flicks, then press Copy in the render report --
|
|
the input log that comes back is what to send back here.
|