Files
MobileGL/docs/Disaggregated/MEASUREMENTS.md
T
swung0x48 8952b14024 [Docs] (Disaggregated): rewrite the MGPipe plan into a design and architecture set - README, ARCHITECTURE, ROADMAP, MEASUREMENTS - and retire PLAN.md and REVIEW.md to git history
- README.md: what MGPipe is, the one-paragraph architecture, the P0 status line, the file and code map, and the commit range where the design competition and the three adversarial review rounds live
- ARCHITECTURE.md: the design as decided, one reason per decision - handles and generations, the 71-call catalogue by class with flags and cap bits, record and payload conventions, the tracker, texture subdata and dirty ownership, shader state and the P0.5 header extraction, the reverse channel, the backend strangler, the server side and the index host mirror, the transport as landed in MG_Remote, the persistent-map tiers as measured, roundtrips, present and threads, process and platform delivery, build shapes and purity gates, the five-part verification gate, and the knob tables marked landed versus planned
- ROADMAP.md: P0..P13 as one table of what lands, the gate and the dependency, the two tracks and milestones, the day-43 GO/NO-GO checklist with both exits, the re-baseline checkpoints, and the questions still open after P0
- MEASUREMENTS.md: spike A on both devices, the spike B tier matrix, the four-trace boundary-counter baselines on both backends, the desktop and corpus facts, and the harness traps with the exact commands
- every file:line kept is verified at 458ccde1 and the citation lint is clean; everything else cites a symbol plus a file
- dropped on purpose: the v1/v2 revision archaeology, rejected alternatives, per-subsystem day estimates, the Feat/CS-Delta-IPC reuse audit and the reviewer back-and-forth
2026-09-05 21:56:31 -04:00

12 KiB
Raw Blame History

P0 实测

每张表都写明设备、提交与命令,以便复现。设备:35d0befa = Xiaomi 24129PN74CAdreno 830Android 163B159D009VZ00000 = Oppo PLG110MaliAndroid 16ColorOS)。设备运行日期 2026-09-05。设备锁协议照旧。

1. Spike A — 从应用自身进程 exec 第二个原生可执行文件

问题:Android 上能否把 server 以 lib*.so 打进 APK,并从应用自己的 untrusted_appfork+execve 它(adb run-as 跑在别的域,证明不了)。

设备 结果
Adreno 830 OK。父进程 u:r:untrusted_app:s0:c173,c257,c512,c768 fork+execve <nativeLibraryDir>/libMobileGLServer.so → 子进程 pid 31348exit 0;子进程 SELinux u:r:untrusted_app:s0:c173,c257,c512,c768(同域同 category);marker 文件、stdout 捕获、报告全在;execErrno=0;窗口内零 avc denial
Mali OK,同形:子进程 pid 28433exit 0execErrno=0u:r:untrusted_app:s0:c94,c257,c512,c768,零 avc denial

主机侧已证的三条(随 8a239177):AGP 会把改名成 lib*.soadd_executable 打进 lib/arm64-v8a/,前提是把 RUNTIME_OUTPUT_DIRECTORY 重定向到 CMAKE_LIBRARY_OUTPUT_DIRECTORYposix_spawn 在 minSdk 26 不可用(bionic API 28 起),出货臂是 fork+execve;应用进程 stdout/stderr 是 /dev/null,子进程用 marker 文件证明自己活过。

  • 代码:tools/spikes/server_stub/main.cppstub:打印并写 marker 自己的 pid/uid/SELinux 上下文)、android-plugin/app/src/trace/cpp/spawn_spike.cppRunSpawnSpike)、CMakeLists.txt:784-808MOBILEGL_BUILD_SERVER_SPIKE)。
  • APKp0-spike-a-android/trace-debug-spike-on.apk(在 30d7595b 构建,与 7ef7c7e5 源码相同)。
  • ColorOS 陷阱:首次 adb install 一个未安装的包会卡在 com.oplus.appdetail InstallGuideActivity 确认页,直到点"继续安装"1272×2772 面板上 input tap 353 2349);同签名重装静默通过。另一台设备上一个外来签名的 trace APKversionCode 26080769)会让 install -rINSTALL_FAILED_UPDATE_INCOMPATIBLE,需先卸载。
  • 42-device.sh 的 env 透传 A/B 腿在该 ROM 上跑不了(run-as sh -c 'cat > files/…' 被拒);透传由下面的 stats 基线端到端证明(--env MOBILEGL_PIPE_STATS=1 必须在 mobilegl.log 里产生 MGPipe stats 行)。

2. Spike B — 跨进程外部内存分档

问题:AcquirePersistentMap 背后的内存能否共享给另一个进程并在那里映射,两个后端各走哪条路。探针 tools/spikes/extmem_probe/39f982e6 源码,arm64adb shell = u:r:shell:s0 域),4 MiB payload,64 KiB 同判决。每一行都取一次真 GPU 访问(vkCmdCopyBuffer + vkCmdFillBuffer + host-read barrier)并两侧字节校验才算 OK。

路线 Adreno 830 Mali
T1-opaque-fdserver 导出 VkDeviceMemory fdclient 裸 mmap + 导入) OK 完整往返含 GPU 访问(/dmabuf:systemdedicatedOnly=1 UNSUPPORTEDvkCreateBuffer(external)=VK_ERROR_INVALID_EXTERNAL_HANDLEadvertisedExportable=0
T1-dma-buf UNSUPPORTEDVK_EXT_external_memory_dma_buf 缺) UNSUPPORTED
T1-gles-memobj-fdGL_EXT_memory_object_fd 导入导出的 fd FAIL:导入 + glBufferStorageMemEXT 接受(GL_NO_ERROR)但每次 glMapBufferRangeGL_INVALID_OPERATIONpersistent 与 plain 都是);GL_DEVICE_UUID 不可读 UNSUPPORTED(扩展字符串缺,入口点可解析)
T0-ahb-blob-transferclient 分配 AHardwareBuffer BLOB → socket 交接 → server Vulkan 导入 + GL 导入) OK 全链:cpu-lock、vk-import+map、GPU copy/fill、GL map persistent+coherent、写回 client 全部字节校验 OK 全链,判决相同(glPersistentCoherent=1gpuRan=1
T3-external-memory-hostVK_EXT_external_memory_host UNSUPPORTED(扩展缺) PARTIAL:导入 + map 往返,但 GPU 写对宿主映射不可见(只读档)
T3-memfd-cross-process / client-memfd-server-import UNSUPPORTED OK / PARTIAL(同样的 GPU 只读 caveat

P11 的分档决定:唯一在两台设备、两个后端上都是完整读写的档是 T0——client 分配 AHardwareBuffer BLOBserver 以 VK_ANDROID_external_memory_android_hardware_bufferMagma)或 EGL_ANDROID_get_native_client_buffer + glBufferStorageExternalEXTEspryt)导入,两侧 persistent+coherent 映射。Adreno 另有 T1Vulkan 路径);Mali 无任何 server 导出路线,host-pointer 导入只读。Caveat:运行域是 shell 不是 untrusted_appAHB 的 socket 交接是每个与 SurfaceFlinger 共享 buffer 的应用都在走的路径,域风险在 memfd/opaque-fd 腿上。

复现:

ANDROID_NDK=$HOME/android-sdk/ndk/27.3.13750724 tools/spikes/extmem_probe/build_android.sh /tmp/extmem-build
S=<serial>; adb -s $S push /tmp/extmem-build/extmem_probe /data/local/tmp/extmem_probe \
  && adb -s $S shell "chmod 755 /data/local/tmp/extmem_probe && /data/local/tmp/extmem_probe; echo EXIT=\$?" | tee out-$S.txt

判决语义(OK / PARTIAL / FAIL / UNSUPPORTED)与逐腿 trace 格式见 tools/spikes/extmem_probe/README.md。主机构建(lavapipe)用来证明探针本身报得对:T1/T3 在 lavapipe 上全 OKT1-gles 在 llvmpipe 上 GL_OUT_OF_MEMORY 是 Mesa interop 缺口,不是探针缺陷。

3. 边界计数器基线(双设备、双后端、四条 trace)

MOBILEGL_PIPE_STATS=1 经 retrace 通道的 --env 透传;trace APK 从 7ef7c7e5 构建,spike OFF。取每次运行的最后一个完整 120 帧窗口。accessor/draw 与 memo 门数字是软件确定的(同一 trace 在两台设备上完全相同:它们数的是代码路径不是硬件),只有墙钟/CPU 时间随设备变。

trace(窗口内帧数) 后端 draws/f acc/draw buf B/f tex B/f(发射 box/rect ubo-global B/f ubo-named B/f memo 门(hit/miss
minecraft-1.21.4-in-world360 Espryt 91.6 9.28 13.5 K 635 K185 box / 0 rect 16.7 K 0 ers 9257/2577etl 10538/1296eub 10720/1114
minecraft-1.21.4-in-world360 Magma 91.6 8.56 13.5 K 39.9 K97 box / 89 rect 16.7 K 0 mfp 0/10994mpm 9240/1754mdt 9120/1874
minecraft-1.21.4-fabric-iris-bsl-in-world120memo 冷) Espryt 23.2 21.04 32.6 K 8.8 K 1.8 K 0 ers 1958/1843etl 722/3079
minecraft-1.21.4-fabric-iris-bsl-in-world120memo 冷) Magma 23.2 11.26 313 K 256 K 1.8 K 0vtxc 1.7 K mpm 1890/895mdt 1573/1212
improved-transparency-minecraft-26.31200 Espryt 1320 8.44 333 K 0 0 0 ers 156925/2791etl 148606/11110eub 148246/11470
improved-transparency-minecraft-26.31200 Magma 1320 6.53 173 K 0 0 331 K mfp 21360/137036mpm 134421/2615mdt 156611/1785
minecraft-1.21.1-neoforge-create-indirect-in-world 两者 两台设备都失败(§5),且不足 120 帧

门缩写:ers = EsprytRenderStateetl = EsprytTextureSyncListeub = EsprytUnitBindingsEpochmfp = MagmaDrawFastPathmpm = MagmaPipelineMemomdt = MagmaDynamicTailMobileGL/MG_Util/Metrics/PipeStats.h:46-122)。accessor-calls 是约 10 个热入口的静态计数,是每 draw accessor 数的下界(站点清单 MobileGL/MG_Util/Metrics/PipeStats.cpp:16-100)。

对设计的读法:

  • 真机稳态动态 accessor 成本是每 draw 6.59.3 次(预测区间 1025 的下沿;llvmpipe 的 15.5/20.7 是 memo 冷的)。推送要打败的是 ~8 次 accessor + memo 探测,不是 124/169 的静态调用点数。GO/NO-GO 的 tracker 绝对 ns 上限从这里定。
  • stage-ubo-namedD-B8Magma 在 26.3 世界每帧重打包 331 KB 具名 UBO 字节,Espryt 直接绑定为 0——host payload 决定的第一个真数字。
  • union box vs region listvanilla 世界同样 185 次发射,Espryt 的整 box 路径移动 635 K 纹素字节/帧,Magma 的 rect 路径 40 K16×——"server 选上传形状"这一条的量化依据(Mali 侧的 +6 ms/frame 作业数悬崖在另一个方向)。

复现(一台设备一次;两台必须串行,见 §4):

ANDROID_SERIAL=<serial> MSYS_NO_PATHCONV=1 \
python3 tools/trace_replay/run_android_retrace_local.py \
  --case minecraft-1.21.4-in-world --backend DirectGLES \
  --env MOBILEGL_PIPE_STATS=1 --env MOBILEGL_PIPE_STATS_PERIOD=120
# 数字在结果目录的 mobilegl.log 里,grep 'MGPipe stats:',取最后一个完整窗口

4. 桌面数据点与语料事实

  • llvmpipe / lavapipe 动态 accessorGuiBatchScenario14 帧 / 26 drawmemo 冷):Espryt 20.65 / Magma 15.54 次/draw——落在预测区间内,且因场景太短偏高;真机稳态数字见 §3。
  • dirty-surface 面python3 scripts/gen_pipe_dirty_surface.py --summary,本树):MG_Impl/GLImpl 41 个文件,926 次 mutator 调用,73 个不同 mutator;92 次(36 个即时发布点、7 个 mutator,836 次里绝大多数是 RecordError)位于同函数内也到达后端的入口,其余 834 次由紧随的 verb 发布。映射表是 73 条目的问题。
  • 读点覆盖python3 scripts/gen_pipe.py):71 条调用(11 screen / 60 context)、63 个 verify payload、61 个 PipeInputs 字段;477 行后端读点清单 → 299 调用、5 client 自答、6 反向通道、167 结构性句柄、0 UNMAPPED
  • OOM 探测惯用法41 个 trace fixture 中 0 例——全部语料只有 9 次 glRenderbufferStorage 调用散在 5 个 fixture,无一在其后 3 个调用内跟 glGetError;语料里真实的成功性检查是 glCheckFramebufferStatus。→ glRenderbufferStorage* 不 ack。
  • FramebufferSrgb / DepthClampFramebufferSrgb 的六个后端读点全部消费一个编译期常量 falseDepthClamp 零读点;两者的 glEnable 落到 RenderState.cppdefault: 分支既不存储也不报 GL_INVALID_ENUM41 个 fixture 无一开启任一项(补真存储不会改动任何既有 fixture 的输出)。
  • GetIntegeri_vEspryt 实现里是 GetIntegeri_v 的 9 个分支 + GetInteger64i_v 的 2 个(不是"15 个 case");GL_COMPUTE_WORK_GROUP_SIZEGL_Program.cppProgramObject::GetComputeLocalSize 纯前端回答。
  • payload 尺寸MG_Pipe/MGPipeTypes.hstatic_assertarm64 与 x86-64 一致):MGPDrawInfo 56MGHostSpan 32、MGPBindRenderState 12MGPResourceDesc 88、MGPFramebufferState 304、MGPProgramDesc 192、MGPSubData 72、MGPPixelPackState 28、ResidualValueBlock 1248(其中 RenderStateParameters 1168)。SEG_CMD 按 56 B 固定头定尺:MC 帧 10004000 draw 时每帧 56224 KiB 头字节。
  • persistent map 采纳的既有基线devMC 26.3Adreno):≥16 MiB 可变 store 定义时采纳为 coherent persistent map 后 p99 163→21 ms、稳态 40→115 fps、省 ~400 MB。P11 的回归上限对着它。
  • Mali 上传作业数悬崖(Espryt 代码注释记录的既有实测):~100 个精灵 rect 对一个 union box 是 +6 ms/frame。

5. Harness 事实与陷阱

  1. trace app 从不到达 MobileGL::DestroyImpl,所以 MOBILEGL_PIPE_STATS_FILE 的 JSON 转储在设备上永远不会写——只有 mobilegl.log 里的周期汇总行;短于一个周期的 trace 什么都不产出。MOBILEGL_PIPE_STATS_PERIOD458ccde1)为此而加:需要数字的运行把它设到足够小。
  2. run_android_retrace_local.py 每棵树共用一个 .trace-work/android-retrace-result 根并在每次调用时 rmtree,所以两台设备必须从一棵树串行跑。
  3. --env 值里嵌入的 /data/... 会被 runner 的 bash.exe 做 MSYS 路径转换(MSYS2_ARG_CONV_EXCL="/data/*" 只覆盖开头匹配)——用 MSYS_NO_PATHCONV=1 跑。
  4. coherent_as_flush 管线完好:--ez coherent_as_flush truetrace_replay_core.cppsetenv,独立于 --env 透传。
  5. minecraft-1.21.1-neoforge-create-indirect-in-world 在两台设备上都失败Adreno 830Espryt ~4.5 分钟后黑帧,Magma 纹理上传提交时 VK_ERROR_DEVICE_LOSTMaliSSIM 0.85 / 0.45)。Adreno 830 上用 dev@81b17c0b 基线 APK 复现,是基线就有的问题,不是本分支造成;它是 P3a/P8 验收清单里的用例,需先在 dev 修。