26 KiB
P15 scoreboard: FCL MC 1.21.5 vanilla at cpuhunt
One row per bench session. MobileGlues (plugin com.fcl.plugin.mobileglues) is the only control
measured in every session. Results are reported as fps ratio to MobileGlues. "vs dev" is derived
through the fixed dev reference below: vs dev = (arm / MobileGlues) / (dev / MobileGlues).
Targets (PLAN-P15 §0.1):
- Monolith at or above dev, then on par with MobileGlues (ratio 1.00).
- Inproc substantially above MobileGlues.
Dev reference (fixed)
Re-measure only when the scene, clock profile, MC version, FCL build or harness changes.
Measured in session safter (2026-10-08 ~22:00) on harness H2 at cpuhunt (CPU 1.50/1.25 GHz, GPU 903 MHz). All
15 runs were VALID, with no throttling (tpl=0 thr=0) and peak CPU 63 C. dev = 08124c99 (perf-dev worktree, libs/devsym). The table gives
3 interleaved reps per arm; CPU is the GL thread's schedstat time.
| arm | fps (r1 / r2 / r3) | mean fps | ratio to MG | CPU ms/frame |
|---|---|---|---|---|
| MobileGlues | 318.8 / 325.1 / 320.5 | 321.5 | 1.000 | 1.70 |
| dev Espryt monolith | 297.1 / 277.3 / 281.0 | 285.1 | 0.887 | 2.38 |
| dev Magma monolith | 313.8 / 294.5 / 308.4 | 305.5 | 0.950 | 2.01 |
- vs dev for a session row: Espryt = ratio / 0.887, Magma = ratio / 0.950.
- CPU reference: dev Espryt 2.38 ms/frame (1.40 of MG), dev Magma 2.01 ms/frame (1.18 of MG).
- Dev reps spread more than the other arms (6-7 % vs 1-3 %): dev's warmup needed 2-5 windows to settle where p15s and MobileGlues needed 2. The mean of the three reps is the reference.
- Function-level baseline: one symbolized simpleperf profile per dev backend, taken after the measurement windows in the same runs:
runs/safter/dev-Direct{Vulkan,GLES}-r{1,2,3}/perf.data. See MONOLITH-DIFF.md.
Harnesses
- H1 (old probe, through fifi):
- Not pinned: the scheduler gave MobileGL's monolith render thread the X4 core 72-90 % of the time and MobileGlues' 47-60 %. MobileGlues' fps tracked its X4 share (fifi: 60 % -> 378, 47 % -> 344).
- fps sources differ by arm: MobileGL arms used the MobileGL fps log before tracing; MobileGlues used the ftrace window.
- Unfrozen world: daylight cycle on, and time advanced between runs through autosaves.
- 2 reps per arm.
- H2 (
fcl_bench.sh, from safter):- FCL is pinned to cpu2-6 (the A720 cluster) after world entry.
- fps for every arm comes from the SurfaceView BLAST layer's frame number in SurfaceFlinger.
- The same warmup for every arm: 20 s, then 5 s windows until two consecutive ones agree within 3 %.
- Measurement: two 5 s windows with no tracer running. Per-thread CPU comes from schedstat over those windows.
- Frozen save: no daylight, weather or mob-spawn cycle, random ticks off, DayTime 6000.
- 3 interleaved reps per arm.
- H2 absolute fps is lower than H1 because nothing runs on X4. Compare H2 rows only with H2 rows.
Sessions
Each cell is the fps ratio to MobileGlues, with presenting-thread CPU in ms/frame in brackets.
- Monolith: the CPU is the GL thread.
- Inproc: the CPU is the apply thread (it presents). The H1 rows use the MobileGL fps log's "presenting thread CPU".
- MobileGlues (MG) cells give fps and CPU.
- A dash means the arm was not in that session.
| session (2026-10-08) | harness | build | MG fps (cpu) | mono Espryt | mono Magma | inproc Espryt | inproc Magma |
|---|---|---|---|---|---|---|---|
| hunt2 14:20 | H1 | p15l ≈ c8a5abe5 |
335.0 (1.58) | 0.80 (2.19)¹ | 0.79 (2.18)¹ | 0.87 (1.63) | 0.92 (1.60) |
| apab 14:51 | H1 | p15m ≈ 500b63ea |
328.6 (1.55) | 0.86 (2.06) | 0.85 (1.96) | 0.90 (1.65) | 0.91 (1.58) |
| blab 16:17 | H1 | p15n/p15o = c07b8c40 | 354.9 (1.46) | 0.84 (2.02)² | - | 0.95 (1.58) | 0.94 (1.53) |
| nxab 17:04 | H1 | p15p = 61b5eb5a | 375.5 (1.43) | 0.81 (1.95) | 0.84 (1.77) | 0.93 (1.54)³ | 0.89 (1.54) / 0.93³ |
| cens 18:09 | H1 | p15r = e00db8e6 |
321.9 (1.57) | - | - | 0.93 (1.50) / 0.99³ | 0.96 (1.46) / 0.99³ |
| fifm 20:07 | H1 | p15s = 0b96a3ef |
361.4 (1.48) | 0.82 (1.98) | 0.84 (1.84) | - | - |
| fifi 20:47 | H1 | p15s = 0b96a3ef |
361.1 (1.47) | - | - | 0.96 (1.37) | 0.94 (1.39) |
H2 sessions:
- Cells are the fps ratio to MG, then vs dev, then GL-thread CPU in ms/frame.
- Inproc cells add the apply-thread CPU.
| session (2026-10-08) | build | MG fps (cpu) | mono Espryt | mono Magma | inproc Espryt | inproc Magma |
|---|---|---|---|---|---|---|
| safter ~22:00 | p15s = 0b96a3ef |
321.5 (1.70) | 0.746 / 0.84 dev (3.18) | 0.768 / 0.81 dev (2.91) | - | - |
| pt ~23:00 | p15t = 3def5cb2 (p15s + Magma blit cache); inproc Magma also p15s | 319.0 (1.69) | 0.755 / 0.85 dev (3.17) | 0.787 / 0.83 dev (2.83) | - | p15s 1.019 (1.36 / 1.42); p15t 1.032 (1.37 / 1.39) |
| c1 ~00:30 (10-09) | t = p15t; u = p15t + cut 1 (in-frame uploads, local) | 324.8 (1.69) | - | t 0.782 / 0.82 dev (2.80); u 0.769 / 0.81 dev (2.86) | u 0.997 (1.38 / 1.63) | u 1.011 (1.37 / 1.39) |
| c1b ~02:10 (10-09) | t = p15t; v = p15t + 1b (coalesced pass barriers, local) | 320.9 (1.69) | - | t 0.783 / 0.82 dev (2.85); v 0.789 / 0.83 dev (2.85) | - | v 1.048 (1.34 / 1.345) |
| c4 ~02:55 (10-09) | v (as c1b); w = v + cut 4 (Espryt surface-size memo, 66e3b2c1) | 321.6 (1.70) | v 0.757 / 0.85 dev (3.18); w 0.762 / 0.86 dev (3.05) | - | - | - |
| c1c2 ~03:30 (10-09) | t = p15t; y = p15t + 1b + 1c (deferred clears) + cut 4 | 321.3 (1.70) | - | t 0.795 / 0.83 dev (2.83); y 0.785 / 0.82 dev (2.74)⁴ | - | t 1.025 (1.35 / 1.41)⁵; y 1.076 (1.33 / 1.24) |
| fbm ~05:20 (10-09) | y (as c1c2); z = y + FB-state build memo, one entry per target | 321.7 (1.70) | y 0.770 / 0.87 dev (3.04); z 0.775 / 0.87 dev (3.04) | y 0.818 / 0.86 dev (2.65); z 0.831 / 0.87 dev (2.65) | - | - |
| fbm2 ~11:00 (10-09) | y; z (as fbm); h = y + batch h (485dff14 + c85c9439) |
319.7 (1.68) | y 0.763 / 0.86 dev (3.03); h 0.768 / 0.87 dev (3.00) | y 0.805 / 0.85 dev (2.68); z 0.798 / 0.84 dev (2.69); h 0.812 / 0.85 dev (2.62) | - | - |
| lto ~17:30 (10-09) | o = ca0a3b74 + 2a/2b, -Pmobilegl.enableLto=OFF; l = the same, LTO ON (default) | 314.1 (1.71) | o 0.794 (2.99); l 0.800 (2.90) | o 0.850 (2.52); l 0.907 (2.36) | - | - |
| api29 ~19:00-21:30 (10-09) | a26 = 0650608d + e543e289 (default, API 26); a29 = the same tree, -Pmobilegl.androidApi=29 (42922d21); both LTO ON |
324.6 (1.67) | a26 0.771 (2.87); a29 0.777 (2.85) | a26 0.874 (2.33); a29 0.910 (2.26) | a26 0.998 (1.27 / 1.53); a29 1.013 (1.22 / 1.50) | a26 1.088 (1.23 / 1.16); a29 1.136 (1.15 / 1.09) |
| tls ~22:00 (10-09) | b = origin e70925d3 (libs/egc); t = tlshoist d4a00835 (libs/tls1); both LTO, API 26 |
318.6 (1.67) | b 0.805 (2.84); t 0.812 (2.79) | b 0.878 (2.35); t 0.933 (2.21) | - | - |
-
pt: the blit view cache gives Magma inproc +1.2 % fps, with apply −0.03 ms/frame.
-
c1: cut 1 is within noise (−1.7 % fps, +0.06 ms). It engaged (the mid-frame submit is gone) but saves ≤0.04 ms; see MONOLITH-DIFF.md.
-
c1b: neutral in monolith on CPU and on GPU (busy 29 % in both). Barriers fell from 27.5 to 15.5 per frame, but passes only from 12.6 to 11.5.
-
c1c2: Magma per frame, from the counting build:
- passes 11.5 -> 4.3 (dev 4.1);
- barriers 15.5 -> 9.0 (dev 3.4);
- Vulkan calls 343.5 (dev 331.6).
Effect:
- Monolith GL-thread CPU −0.09 ms/frame (2.83 -> 2.74); fps within noise.
- Inproc apply thread −0.17 ms/frame (1.41 -> 1.24) and fps +5.0 % (329.5 -> 345.7).
- GPU busy: monolith 30 -> 27 % (≈1.18 -> 1.07 GPU ms/frame); inproc 35 -> 33 % (≈1.06 -> 0.96).
- Profile: the
glClearentry fell 0.286 -> 0.098 ms/frame. Part of that pass begin moved into draws (DrawArrays +0.07).
⁴ y has 2 valid reps: r2 never reached the world after 3 startup deaths (signal 34 during bootstrap, a harness flake also seen on MobileGlues and other builds). ⁵ t inproc r2 is discarded: a host-side
binary_cache_builderpulled libraries over adb inside its measurement window. -
fbm2: batch h moves GL CPU by -0.06 ms (Magma) and -0.03 ms (Espryt).
- Batch h: per-framebuffer FB-state memo, handle hints, per-buffer handle reuse, the cached per-verb gate, and the Magma hash TLS hoist.
- The Magma before/after profile (render thread, ms/frame, c1c2 y-r1 -> fbm2 h-r1):
- MGPipeValidateForVerb 0.328 -> 0.282, BuildFramebufferState 0.058 -> 0.023;
- FindByLifetimeId + Acquire 0.047 -> 0.003, __emutls_get_address 0.079 -> 0.054;
- GetOrCreatePipeline 0.026 -> 0.013, MGPipeGetResourceOps 0.007 -> 0.002.
- The H2 effect is about half of the profile sum. Each piece is below the session noise (+-0.05 ms), so the batch is measured as one.
-
lto: ThinLTO + -O3 + ICF/gc/no-semantic-interposition (190580f2) takes GL CPU from 2.52 to 2.36 ms on Magma (fps 267 -> 285) and from 2.99 to 2.90 on Espryt. All runs VALID.
- Both backends load and render in FCL (one screenshot each, runs/lto-shot).
- Exported GL/EGL/JNI/vk symbols are identical (2973). LTO drops 3323 internal 3rdparty C++ exports.
- libMobileGLServer.so links and its only libMobileGL import (mobilegl_server_main) is exported.
-
api29 (cpuhunt, vanilla 1.21.5 frozen world, 3 interleaved reps, one bench session per rep with the arm order rotated, 27 of 27 runs VALID): API 26 (shipped, emulated TLS) against API 29 (separate artifact, native ELF TLS), the same tree, both LTO ON.
-
Libs: api26
b843b121..., 0 TLSDESC relocs, 98__emutls_v.*symbols; api291f2ec4a0..., 95 TLSDESC relocs, a PT_TLS segment, 3__emutls_v.*(libc++abi). Both load and render in FCL. -
fps, mean of 3 (api26 -> api29, ratio) and GL / apply thread CPU ms/frame:
arm fps 26 fps 29 29/26 GL cpu 26 -> 29 apply cpu 26 -> 29 Magma monolith 283.7 295.5 1.041 2.33 -> 2.26 (0.970) - Magma inproc 353.1 368.6 1.044 1.23 -> 1.15 (0.930) 1.16 -> 1.09 (0.945) Espryt monolith 250.2 252.2 1.008 2.87 -> 2.85 (0.994) - Espryt inproc 324.0 328.7 1.015 1.27 -> 1.22 (0.966) 1.53 -> 1.50 (0.978) MobileGlues (control) 324.6 (1.67 ms) -
Per-rep fps: Magma mono 277.5 / 291.6 / 282.2 vs 298.5 / 286.2 / 301.9 (rep 2, where api29 ran first, is the one rep it lost by 1.9 %); Magma inproc 351.9 / 354.9 / 352.4 vs 365.3 / 374.6 / 365.9 (api29 ahead in every rep); Espryt mono 251.9 / 249.1 / 249.4 vs 253.6 / 248.0 / 255.1; Espryt inproc 327.1 / 314.9 / 329.9 vs 324.1 / 326.6 / 335.3. Spread (max-min)/mean is 0.8-5.3 %: the Magma inproc gain (+4.4 %, spread 0.8 / 2.5 %) is outside it, Magma monolith (+4.1 %, spread 5 %) is about at it, both Espryt gains are inside it.
-
Device state, every run: CPU 1497 (cpu2-6) / 1248 (cpu0) / 1478 (cpu7) MHz, GPU 903 MHz, samples inside the measure windows only; tpl 0, throttling 0, no "max capped"; peak over the 27 runs CPU 62.8 C, GPU 56.2 C, skin 43.9 C; daemons stopped during a session and restored after (5 running again, max clocks back to stock); swap=false; anland off; FCL pinned to cpu2-6 (taskset 7c); cooldown to battery <= 33.0 C before each session.
-
Simpleperf, one run per cell (monolith render thread, 6 s, cpu-clock 4000 Hz;
runs/api29ab-sp). The share of TLS access in the render thread's on-CPU time:cell on-CPU ms/frame TLS symbol ms/frame share Magma api26 2.546 __emutls_get_address0.052 2.1 % Magma api29 2.501 tlsdesc_resolver_dynamic(linker64)0.051 2.1 % Espryt api26 3.016 __emutls_get_address0.058 1.9 % Espryt api29 3.259 tlsdesc_resolver_dynamic(linker64)0.047 1.4 % -
Reading:
- API 29 does not remove the TLS cost of the monolith render thread. MobileGL is dlopen'ed, so bionic resolves each TLSDESC through the linker's dynamic resolver (
tlsdesc_resolver_dynamic), a call that costs about what__emutls_get_addressdid (0.05 ms/frame, about 2 % of the thread). The native-TLS switch is therefore not the source of the Magma gain; whatever it is (code layout and codegen of a different link, or the android-29 platform), this A/B does not isolate it. - Untested lead for a real TLS saving: a static TLS model (initial-exec) for the hot variables. Bionic's room for static TLS in a dlopen'ed library is limited, so it needs its own measurement.
- The Espryt monolith profile run read 242.6 / 245.4 fps against 252.2 / 254.0 for api26, opposite to the 3-rep means; it is one run, the 3 interleaved reps decide.
- API 29 does not remove the TLS cost of the monolith render thread. MobileGL is dlopen'ed, so bionic resolves each TLSDESC through the linker's dynamic resolver (
-
-
tls (cpuhunt, 3 interleaved reps, all 15 runs VALID, tpl=0 thr=0, peak CPU 57.7-61.3 C): hot-path TLS cut (tlshoist: constinit pointer slots for pGLContext and gPipeInputs, one-block thread_local caches, inline Magma session read). Emulated-TLS calls per frame (counting build, run tlsdiag): Magma 9111 -> 4336, Espryt 7585 -> 3149.
- fps r1 / r2 / r3: Magma b 285.6 / 275.4 / 277.8 (279.6), t 295.1 / 301.4 / 295.2 (297.2, +6.3 %); Espryt b 269.5 / 251.9 / 248.4 (256.6), t 260.6 / 270.6 / 245.2 (258.8, +0.9 %); MobileGlues 318.6.
- GL CPU (schedstat): Magma 2.35 -> 2.21, Espryt 2.84 -> 2.79 ms/frame.
__emutls_get_addresson the render thread (simpleperf, mean of 3 reps): Magma 0.058 -> 0.034, Espryt 0.049 -> 0.035 ms/frame. Magma's MobileGL-side total falls more than that (-0.04 to -0.20 per rep): the callers lose the init-wrapper/guard calls and spills too.- A second session (tlspf, Perfetto, no simpleperf, 12 runs VALID) read Magma 278.6 -> 284.4 fps
(CPU 2.40 -> 2.30) and Espryt 246.2 -> 254.5 (2.94 -> 2.83). Traces in
runs/tlspf/*/p15.pftrace, not analysed yet.
-
bsl3 (gpuhunt, stopped on a CPU max cap in rep 2): r1 Magma 55.6, Espryt 52.8, MobileGlues 57.2 fps. That is Magma 0.97 and Espryt 0.92 of MobileGlues.
-
c1cbsl (gpuhunt, Iris + BSL, after a cooldown, 3 reps): 1c does not cost GPU time.
- VALID runs: t 53.8 / 53.9 fps vs y 55.7 / 55.5 (+3.4 %), all at 100 % GPU busy (18.5 -> 17.9 GPU ms/frame).
- MobileGlues read 56.2 / 55.7 / 56.1, which puts Magma y at about 0.99 of it. All three MobileGlues runs (and t r2, y r2) are INVALID for one reason: the freq sampler's first sample, about 40 s before the windows, catches the idle GPU at 231 MHz. Every in-window sample of every run is at the 578 MHz pin.
- A window-scoped validity check (freqcheck over the measure_raw.txt span) would admit them. That is a harness change, not yet made.
-
ebbsl (gpuhunt, Iris + BSL, Espryt monolith, 3 reps, one arm per cooldown, all VALID): the two parked Espryt GPU items (native depth glCopyImageSubData, attachment shadow) do not help. Builds: x = origin
9f610167+ the items, b = origin9f610167, both LTO; MobileGlues is the plugin.- fps r1 / r2 / r3: x 51.4 / 51.3 / 51.5 (mean 51.4), b 52.7 / 51.8 / 51.0 (51.9), MobileGlues 56.5 / 55.6 / 55.3 (55.8). Ratio to MobileGlues: x 0.921, b 0.930 (x vs b -1.0 %, noise). Target 0.95 not reached.
- GPU: busy 100 % in every run; union of kgsl cmdbatch intervals per frame (x / b / MobileGlues) 19.45 / 19.29 / 17.88 ms, 1.04 cmdbatches per frame in all three.
- Device state: gpuhunt (CPU 2380/1689 MHz, GPU 578 MHz; in-window min = max for every policy), tpl=6 thr=0, peak CPU 75.5-79.4 C, GPU 63.2-65.9 C, skin 42.4-44.5 C, daemons stopped(5), swap=false, anland off.
- Engagement (one simpleperf run each, render thread):
BlitDepthTexture2D0.100 ms/frame in b, gone in x; EsprytCopyImageSubData0.115 -> 0.072;SyncToBackendByHandle0.178 -> 0.162. - Vanilla cpuhunt (1500/1250/903 MHz, 3 reps, all VALID, peak CPU 58 C): Espryt monolith GL CPU x 2.87, b 2.83 ms/frame; fps x 249.9 / 251.4 / 244.2 (248.5), b 250.1 / 256.5 / 255.2 (254.0), GPU busy 17 %.
- Not landed: wip/espryt-depthcopy-measured. The BSL frame is GPU-bound and its GPU time did not move.
-
fbm: the first memo is within noise on both backends (CPU 2.65 / 2.65 Magma, 3.04 / 3.04 Espryt).
- It engaged only partly: Magma BuildFramebufferState 0.058 -> 0.032 ms/frame, and Espryt kept missing.
- The build only runs on a binding switch, so one entry per target misses on every A/B/A switch. Batch h makes it per framebuffer.
- Session noise: y Magma r3 read 2.54 against 2.70-2.72 in r1/r2, with nothing in its state to explain it.
-
c4: Espryt GL-thread CPU fell 0.13 ms/frame (3.18 -> 3.05 in all three reps); fps moved by less than the noise. The profile confirms it: QueryCurrentSurfaceSize 0.070 -> 0.012 and SyncRenderState 0.092 -> 0.028 ms/frame.
Thread state, Perfetto SQL (c1, H2; pftstate.py over trace_processor_shell v58.2 on the
.pftrace taken after the windows; means of 3 reps; ms/frame):
| arm | fps | GL run | GL woken-wait | GL preempted | GL sleep | apply run | apply sleep | both on-CPU / neither |
|---|---|---|---|---|---|---|---|---|
| MobileGlues monolith | 324.8 | 1.91 | 0.036 | 0.030 | 1.05 | - | - | - |
| Magma monolith (t) | 254.1 | 3.09 | 0.042 | 0.027 | 0.71 | - | - | - |
| Magma monolith (u) | 249.8 | 3.05 | 0.045 | 0.045 | 0.79 | - | - | - |
| Magma inproc (u) | 328.3 | 1.43 | 0.047 | 0.073 | 1.45 | 1.61 | 1.31 | 41 % / 41 % |
| Espryt inproc (u) | 323.8 | 1.39 | 0.057 | 0.088 | 1.51 | 1.95 | 1.02 | 42 % / 34 % |
| c1c2: MobileGlues monolith | 321.3 | 1.95 | 0.039 | 0.019 | 1.05 | - | - | - |
| c1c2: Magma monolith (t) | 255.3 | 3.11 | 0.039 | 0.038 | 0.66 | - | - | - |
| c1c2: Magma monolith (y, 1c) | 252.3 | 3.07 | 0.047 | 0.029 | 0.75 | - | - | - |
| c1c2: Magma inproc (t) | 329.5 | 1.38 | 0.050 | 0.073 | 1.48 | 1.58 | 1.32 | 40 % / 42 % |
| c1c2: Magma inproc (y, 1c) | 345.7 | 1.39 | 0.043 | 0.079 | 1.33 | 1.43 | 1.31 | 39 % / 42 % |
The sleeps break down as:
- Monolith (both stacks): the app's
waitForeverslice inside queueBuffer, woken bykgsl-events, i.e. the GPU fence of the previous frame. - Inproc GL thread: woken by
mgl-srv-apply. - Inproc apply thread:
waitForever(the GPU fence), as in monolith.
The table below is the same window from the ftrace text (threadstate.py). It carries GPU busy, because this Perfetto config does not record the kgsl events.
| arm | GL thread on-CPU | preempted | sleeping (main reason) | apply thread on-CPU | apply sleeping | both on-CPU / neither | GPU busy |
|---|---|---|---|---|---|---|---|
| MobileGlues monolith | 61 % (1.88) | 0.03 | 37 %: present fence waitForever 1.13 |
- | - | - | 30 % |
| Magma monolith (p15t) | 78 % (3.08) | 0.03 | 20 %: present fence 0.78 | - | - | - | 29 % |
| Magma inproc (u) | 47 % (1.42) | 0.11 | 48 %: woken by the apply thread 1.45 | 52 % (1.59) | present fence 1.30 | 40 % / 41 % | 36 % |
| Espryt inproc (u) | 47 % (1.45) | 0.10 | 48 %: woken by the apply thread 1.47 | 63 % (1.95) | present fence 1.07 | 44 % / 34 % | 30 % |
What the table shows:
- Monolith Magma is CPU-bound: the GL thread is on-CPU 78 % and preemption is negligible.
- MobileGlues finishes its CPU work sooner, then waits on the present fence.
- Inproc is bounded by present-fence latency at credit 1, not by CPU: the apply thread waits on the fence while the GL thread waits on the apply thread, and for 34-41 % of the time neither runs. The GPU is only 30-36 % busy.
Sources:
.pftracecaptures for the Perfetto UI are inruns/c1/*/p15.pftrace.- The numbers come from the same window's ftrace text via
threadstate.py: no trace processor is installed.
H2 spread, measured as (max - min) / mean over the 3 interleaved reps of each arm:
- sbefore (H1 probe, same day, 3 reps): Espryt 288.6 / 287.7 / 315.2 (9.3 %), Magma 298.0 / 295.0 / 312.0 (5.6 %), MobileGlues 370.2 / 374.7 / 375.1 (1.3 %).
- safter (H2): Espryt 240.2 / 240.8 / 237.9 (1.2 %), Magma 245.3 / 251.3 / 244.1 (2.9 %), MobileGlues 2.0 %, dev 6-7 %.
- The X4 core hid part of the gap: on the A720 cluster, p15s is 0.84 (Espryt) and 0.81 (Magma) of dev. In CPU, that is +0.80 and +0.90 ms/frame over dev.
Notes:
- hunt2 monolith comes from the profiled sub-run (hunt2-prof, simpleperf in the window), so it is not the same sub-session as its MobileGlues control. Dev in that sub-run: Espryt 305.3 (1.64), Magma 302.2 (1.59), that is 0.91 / 0.90 of hunt2's MobileGlues.
- blab monolith Espryt is p15n (p15o has no monolith arm in blab).
- Present credit 2 (
MOBILEGL_IPC_PRESENT_CREDIT=2); the default credit is 1. The FIF sweep (fifm/fifi, FIF 2/3/4) showed no significant effect; FIF 3 is the default and is the column shown.
H1 spread: two reps of the same arm differ by up to 10 % within a session (fifi MobileGlues 378.4 / 343.8, apab p15m Magma monolith 289.3 / 266.6). MobileGlues ranged from 322 to 376 across sessions. H1 ratios therefore carry roughly ±5 %.
egc: global-constants key (e70925d3) vs 0650608d, monolith, cpuhunt, vanilla frozen world
Baseline b = 0650608d, x = e70925d3 (both LTO-ON, API 26), FCL on cpu2-6, simpleperf on the render thread, 3 interleaved reps per arm, all 12 runs VALID (clocks pinned in the windows, tpl=0 thr=0, daemons stopped, swap off). EmitGlobalConstants is inlined under LTO, so its cost is every sample with an EmitGlobalConstants inline frame (llvm-symbolizer --inlines); ValidateForVerb is inclusive.
| backend | arm | fps | GL CPU ms/frame | ValidateForVerb ms/frame | EmitGlobalConstants ms/frame |
|---|---|---|---|---|---|
| Magma | b | 279.4 | 2.39 | 0.190 | 0.0220 (0.021 / 0.025 / 0.020) |
| Magma | x | 274.6 | 2.38 | 0.194 | 0.0142 (0.016 / 0.013 / 0.013) |
| Espryt | b | 249.6 | 2.85 | 0.215 | 0.0214 (0.022 / 0.020 / 0.022) |
| Espryt | x | 252.8 | 2.82 | 0.194 | 0.0136 (0.013 / 0.014 / 0.014) |
EmitGlobalConstants drops by 0.0078 ms/frame on both backends (about 35 %), inside the expected 0.007-0.010. The whole frame (fps, GL CPU, ValidateForVerb) is within noise: ValidateForVerb varies 0.17-0.22 between reps of one arm.
pwab: present-wait levers before/after, cpuhunt, vanilla frozen world (2026-10-10)
Before = a759b4b7. After = pwgate cdd2160f (lever A) + pmflush eec5e6e8 (cherry-picked on cdd2160f); Magma "after" also has MOBILEGL_MAGMA_EXTRA_SWAPCHAIN_IMAGES=2 (lever B). All libs LTO-ON, API 26 plugin release (libs/pwbase, libs/pwAF, libs/pwA, libs/pwF). Harness H2 (fcl_bench.sh), FCL on cpu2-6, 20 s warmup then 5 s windows until stable within 3 %, two 5 s measurement windows, no tracer. 3 interleaved reps in one bench session each (arm order rotated, battery <= 33.0 C before each session), thermal daemons stopped, swap interval 0, anland off. All 26 measured runs VALID (CPU pinned 1497/1248 MHz, GPU 903 MHz, tpl=0 thr=0). Espryt monolith "before" has reps 1 and 3 only: rep 2 was NO WORLD (FCL never reached the world in 4 launches) and was not re-run, by user decision.
Inproc first (the wanted numbers). fps = mean of the two windows; ratio is to MobileGlues' mean in the same sessions (315.7 fps; 305.6 / 320.7 / 320.9; CPU 1.69 ms/frame).
| arm | fps r1 / r2 / r3 | mean | after / before | ratio to MG | GL-thread CPU | apply-thread CPU |
|---|---|---|---|---|---|---|
| Magma inproc before | 334.1 / 359.6 / 378.8 | 357.5 | 1.132 | 1.19 | 1.12 | |
| Magma inproc after (AF + extra 2) | 442.2 / 478.9 / 494.6 | 471.9 | 1.32 (1.32 / 1.33 / 1.31 per rep) | 1.495 | 1.13 | 1.12 |
| Espryt inproc before | 302.1 / 332.9 / 325.8 | 320.3 | 1.014 | 1.26 | 1.54 | |
| Espryt inproc after (AF) | 323.0 / 366.4 / 354.5 | 347.9 | 1.09 (1.07 / 1.10 / 1.09) | 1.102 | 1.27 | 1.49 |
| Magma monolith before | 251.2 / 300.0 / 282.1 | 277.8 | 0.880 | 2.39 | ||
| Magma monolith after (AF + extra 2) | 352.9 / 390.6 / 369.9 | 371.2 | 1.34 (1.41 / 1.30 / 1.31) | 1.176 | 2.22 | |
| Espryt monolith before | 238.2 / NO WORLD / 252.9 | 245.6 (r1, r3) | 0.778 | 2.89 | ||
| Espryt monolith after (AF) | 260.3 / 300.0 / 288.8 | 283.0 | 1.12 on r1+r3 (1.09 / 1.14), 1.15 on all reps | 0.896 | 2.70 |
- Reps drift upward with time (MobileGlues 305.6 -> 320.9 over the three sessions), so compare per rep. The after/before ratio is stable within a backend (Magma 1.30-1.41, Espryt 1.07-1.14).
- Engagement, from logcat in every Magma after run (mono and inproc):
Set minImageCount = 7 (surface min 5, max 64, extra 2)and the latched "off-screen work goes to the queue ahead of its window pass" line; neither appears in the before runs. From the single Perfetto runs (runs/pwlat): QueueSubmit per frame 1.30 -> 2.25 (mono) and 1.25 -> 2.20 (inproc), as expected for lever A. - Espryt has no log marker for lever A or pmflush (F). The CPU drop on the monolith (2.89 -> 2.70 ms/frame) fits the saved copy jobs, but A and F were not separated and no profile was taken (user scope cut), so their individual shares are unmeasured.
- Expectations that failed (lever B): the HANDOFF predicted
HWC release fence ... has signaledat >= 85 % of acquires and < 20 % gated frames. The single Perfetto runs show 58 % signaled / 37 % gated (Magma mono) and 66 % / 33 % (Magma inproc). The fps gain is larger than the sim's upper bound for lever B alone (Magma mono frame 3.60 -> about 2.9 ms, i.e. +24 %; measured 3.60 -> 2.70), so something beyond the modelled throttle moved. Not investigated: the timeline analysis was cut; the traces are for the follow-up. - Presenting-thread CPU barely moved on Magma (2.39 -> 2.22 mono, 1.19 -> 1.13 inproc): the gain is frame time, not CPU.
- Single Perfetto runs, one per arm (not part of the fps table; fps of those runs: Espryt mono 250.1 -> 296.0, Espryt inproc 330.6 -> 357.1, Magma mono 302.2 -> 378.8, Magma inproc 369.6 -> 468.9):
p15/runs/pwlat/{b,AF}-DirectGLES{,-inproc}-r1/p15.pftraceand{b,AF2}-DirectVulkan{,-inproc}-r1/p15.pftrace. All eight are non-empty (19-22 MB, 4.9 s), have the frametimeline (812-835 actual frames) and the FCL presenting thread (Thread-14 mono, mgl-srv-apply inproc). Config: p15_perfetto.cfg without kgsl/* events (p15/pw/dev/perfetto.cfg). - A partial first attempt with Perfetto in every run (Espryt mono b, A, F, AF) was cancelled by scope change:
runs/pwab0-pf-partial.