cmux-next iPhone Feed: scroll perf rig and findings (row changes not yet proven)
Summary
Draft: the investigation and the Feed perf rig. The row-level changes are not proven to help, so this is not ready to land as a speedup. Details and numbers are in cmux-next-ios/verify/feed-perf-20261021.md.
Rig (cmux-next-ios/verify/feedperf/, DEBUG and Demo only):
- Realistic Feed pressure: permission cards with long commands, questions, failed and finished cards, markdown with code and tables, quotes, two Macs and replies, plus a live insert at the top like live mode's.
- Main-thread CPU per frame in the frame log, so a late frame can be tied to the app's own work.
- The churn log is opt-in. It had been reflecting over events on the main thread inside the timed window.
sample-based profiling: xctrace cannot record over SSH on the cmux minis, because Developer Mode is off there.- A run host separate from the build host.
Finding: every hitch is the app's own work, about 14–20 ms of main-thread time each time an approximately 400 pt row scrolls in. That is SwiftUI building and measuring the full row tree. Rows with only an avatar, or plain Text rows, scroll at 0 ms/s.
Row changes on the branch (all reviewed): one-pass cell layouts, a UIKit … menu with a deferred menu, share opened on tap, a lazy long-press menu, UIKit haptics instead of .sensoryFeedback per row, web-body placeholders during a fling, new events held behind the pill while the person reads below the top, an inline-text cache, and a single-shape quote bubble.
In same-hour A/B runs on an iPhone 16 Plus simulator (mini-cmux15, 320 events, 2400 pt/s), base and fix measure the same: about 50–60 vs 60–69 ms/s of hitches, with a main-thread p99 of about 20 ms per frame for both. The < 5 ms/s target is not met. Two earlier single runs at 24–28 ms/s were never reproduced, and no base run was made at that hour.
Changelog
none
Testing
swift test --filter "Feed|TerminalFeed|MultiMac|FrameInterval"on mini-cmux11s: 73 tests in 20 suites passed.- New suites were committed red before their implementation:
FeedHoldNewTests: red at942f5c70c41d, a compile failure becauseisReadingBelowTopdid not exist yet.FeedScrollMotionTests: committed at6b098215f096, before its type existed.
- Demo simulator builds succeeded on mini-cmux11s.
Observed / Not run
- Observed: the frame-log A/B runs and the 1 ms
sampleprofiles listed in the verify notes. - Not run: Instruments traces (xctrace did not record on the minis), the full kit suite (runs in CI), and anything on a device.
Review
A correctness subagent reviewed 7cded2f. Its findings and their resolutions are in a comment on this PR.
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Draft: investigates iPhone Feed scroll hitching with a new performance rig, plus a set of row-level changes that same-hour A/B runs show do not measurably help—the hitches are the app's own main-thread work, about 14–20 ms per ~400 pt row that scrolls in, so this is not ready to land as a speedup.
Finding
- Every hitch is the app's own work: each row that scrolls in costs 14–20 ms of main-thread time; avatar-only and plain
Textrows scroll at 0 ms/s. - Base and branch measure the same in A/B runs (about 50–60 vs 60–69 ms/s of hitches); the < 5 ms/s target is not met.
Changes on the branch
- One-pass cell layouts, a UIKit
…menu with a deferred menu, share opened on tap, a lazy long-press menu, UIKit haptics instead of.sensoryFeedbackper row, web-body placeholders during flings, new events held behind the pill while reading below the top, an inline-text cache, and a single-shape quote bubble. - Rig adds realistic Feed pressure, per-frame main-thread CPU to the frame log, an opt-in churn log,
sampleprofiling (xctrace cannot record over SSH on the cmux minis), and a run host separate from the build host. - Use of held events changes Feed behavior while reading below the top; details and numbers are in
cmux-next-ios/verify/feed-perf-20261021.md.