Repository navigation
Conversation
Instrument only, no behaviour change. `--test-action perf:on`, `OCTOSENSE_PERF=1`, or three quick taps on the status bar's battery icon switch on `Cx::perf_monitor`: - the shell's surfaces are app channels next to the platform's own: `home` (wallpaper, home page, tiles), `module` (hosted apps and tiles drawing into their captures), `glass` (backdrop snapshots, blur pyramids, the compositor's finish), `overlay` (status bar, island, keyboard, navigation), `shade`, `groups`; - the Android backend never closes the monitor's frames, so the phone scene calls `frame_boundary` at the start of every draw; - `PerfGraph` is drawn topmost (above the shade) while the monitor is on, on the frames the shell draws anyway — it schedules none of its own; - every 2 s the shell's tick logs a `[perf]` line read back from the monitor's ring: frames, p50/p95/max gap, missed 16.7/33 ms frames, idle pauses, per-channel ms per frame and what asked for the frames, then a census of what the renderer did without the shell: repaints (the newest `painted_serial`) against phone scenes drawn, the attached passes the latest repaint painted, the events the app saw by kind and timer id, the backend's repaint flags (`demo_time_repaint`, dirty and requested passes, pending draw-item retirements), the retirement-debt term holding them, and any drawn shader that reads the pass time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`launcher::apps()` read `wm/launcher.hides` and `wm/apps.splash` from disk and stat'ed every app's binary on each call, and the phone shell asked for it several times per frame (home layout, pager sync, tiles, groups, launch origins). It now answers from a one-second memo; `apps_uncached()` is the fresh read. A change to the settings shows within a second. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rame `IslandState::step` reported itself active while any auto-finish or countdown was pending, so the demo's 25-minute countdown held the phone at 60 fps for as long as it ran. A deadline within a frame is stepped on the frame loop; a farther one wakes through the shell's 1 s tick (`needs_step`), with a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measured on the OnePlus 6T (perf-before.md): an idle home page presented 54 frames/s at 75 % CPU, Recents 30/s, the group window 42/s; every transition had 33–100 ms frames. - The phone frame loop re-armed whenever the wallpaper was visible, only to drift the wallpaper. It now runs while something animates or a finger is down; the wallpaper's phase advances with those frames and holds still otherwise. The shell's 1 s tick (`phone_tick`) wakes what changes on its own: the status-bar clock, an island timer, the open shade's relative times, a tile client that is still starting. - `PhoneState::scene_plan` decides per frame what the scene needs: the backdrop compositor (a full-screen off-screen scene pass, its copy and a blur pyramid per glass) only when a frosted surface samples the scene — the overview, the shade, a group window, iOS's dock and keyboard — and neither the wallpaper shader nor the home page under a settled, opaque app. With a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rame On the OnePlus 6T the renderer repaints the window at display rate while the shell is idle: makepad's retained-upload ledger reports retirement debt (`allocations`) on every render, the GL backend answers with `demo_time_repaint`, and every pass recorded in the latest redraw is painted again — 55 presents/s on an idle home page with the shell drawing one scene a second (the monitor's census: `repaints=113 scenes=2`, `retirement-debt: allocations`). That is upstream; what the shell decides is how much each of those repaints costs. It was three full-screen passes: the window, the `WmScene` framebuffer cache the whole desk renders into, and the desktop wallpaper's `CachedView` inside it. On a phone style the desktop wallpaper is hidden (the phone paints its own) and the scene renders straight into the window: `WmScene::set_caching` switches the view through `set_optimize`, since `View` only reads `texture_caching` when a script is applied. Desktop styles keep the cache and their crossfade. The census now shows the window pass alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nst perf SurfaceFlinger presents and the frame monitor's `[perf]` census for thirteen scenarios on the monitor-only baseline and on this branch, what the fixes changed, and the upstream repaint loop they do not reach. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ymote
force-pushed
the
perf/mobile-shell
branch
from
September 19, 2026 23:56
11041c3 to
a4194b2
Compare
ymote
force-pushed
the
fix/hosted-appcard-mobile
branch
from
September 19, 2026 23:56
fedd802 to
4c7e419
Compare
Contributor
Author
|
Closing as superseded: every commit in this stack (#22–#28) is already on OctoSense-ROM 🤖 Generated with Claude Code |
chrislearn
pushed a commit
to chrislearn/OctoSense
that referenced
this pull request
Sep 29, 2026
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
chrislearn
pushed a commit
to chrislearn/OctoSense
that referenced
this pull request
Sep 29, 2026
…runtime patch Makepad main now carries both halves of patches/runtime/ makepad-isolate-policy.patch: the isolate policy (makepad OctoSense-org#22) and the product fixes (OctoSense-org#26: theme-reload resolver and host widgets, retained eval errors, OpenHarmony capture). So Home locks Octoscript-Makepad 36ad1f22 with an empty runtime-patches lock, which setup now accepts. AppCard's octos-app and the Camera source move to AppCard main 1cf78120. Mail stays on eaf3d145 until its native crate reaches AppCard main. InstanceHandles.windows is left unsupported: on a phone, modules use modals. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes the standalone phone shell draw only when something moves, and measures it on the OnePlus 6T (Snapdragon 845, 1080×2340, 60 Hz) with both SurfaceFlinger (what the display got) and makepad's own frame monitor (what the main thread did). Built on #24 (
fix/hosted-appcard-mobile@ fedd802).How it was measured
perf/mobile-shell-baseline@ 7b253a8: mobile: the hosted AppCard stays in its client slot and its card survives the light theme #24 plus the instrument commit only (below), no fixes.adb shell input(scratchpad/perf_scenarios2.sh):dumpsys SurfaceFlinger --latencyintervals between actual present times.[perf]lines, plus one PerfGraph screenshot per scenario.Table 1 — SurfaceFlinger (display), baseline vs perf
CPU after idle-home: baseline 78.0 % · perf 43.0 %
CPU after idle-app-screen: baseline 41.0 % · perf 34.0 %
Table 2 — makepad frame monitor (
[perf]), baseline vs perfGap = main-thread paint-to-paint interval (p50 / p95 / max ms, with (>16.7·>33) counts). ms/frame columns: event · home · module · glass · overlay · shade · groups. Asked by: a=animation g=gesture x=action e=external (nothing in the shell asked).
scenes/s = phone scenes the shell drew; repaints/s = window repaints the renderer did (census).
How to read Table 2's ms/frame columns. They are per shell frame. At 1 scene/s every event of that second lands on that one frame, so a larger number there is not a slower frame.
What each commit does
--test-action perf:on,OCTOSENSE_PERF=1, or three quick taps on the status-bar battery icon.home,module,glass,overlay,shade,groups) sit next to the platform'seventchannel. The phone scene callsframe_boundary, which the Android backend never does.[perf]line every 2 s gives the gap p50/p95/max, missed frames, per-channel ms/frame, and what asked for the frames (animation, gesture, action, external).launcher::apps()read two settings files and stat'ed every app binary on each call, and the home page called it several times per frame.PhoneState::scene_planroutes a frame through the backdrop compositor only when a frosted surface samples it. It skips the wallpaper shader and the home page under a settled app.CachedViewis hidden.WmScenerenders straight into the window (set_optimize, becauseViewonly readstexture_cachingwhen a script is applied).Found, not fixed here (upstream, makepad fork)
What happens. The renderer keeps repainting the idle window at display rate.
Evidence. On every sample of an idle home page the census reads
retirement-debt: allocations, withdemo_time_repaintset and no dirty or requested passes. The platform repaints about 55 times a second while the shell draws one scene a second (repaints=113 scenes=2).Where it happens. In makepad's GL backend,
retire_free_itemskeeps returning true because the retained-upload allocation ledger (RetainedAllocationBudget::has_pending_retirements) never settles. On every render that setsdemo_time_repaint(opengl.rs:409), andcompute_pass_repaint_orderrepaints every pass recorded in the latest redraw.What was ruled out. The worker pool is healthy (heavy-lane wait 0.26 ms). Events, timers, widgets and shaders are not involved: dropping the only per-frame timer before the app, and drawing one flat quad, both left the repaints unchanged.
Consequence. The display still gets ~55 presents/s on idle screens on both builds. This PR lowers what each of those repaints costs; the repaints themselves need the ledger fixed upstream.
Tests
cargo test264 passed ·cargo test --features mobile-only261 passed.New tests:
Visual check: the home, shade and Recents screenshots match between the builds. The frosted backdrop under the shade and Recents samples the scene upside down on both builds; that is pre-existing (GL snapshot orientation) and not changed here.
🤖 Generated with Claude Code