[Docs] (Disaggregated): P5d round 3 close-out - the report, the measurements section and the roadmap row

- P5D-INPROC-PERFORMANCE.md: the round-2 diagnosis is corrected against the
  symbolized call graph (the apply thread's mutex time was the idle poll, not
  the backend pendingMutex), the four round-3 packages and the two race fixes are
  described, the numbers table carries the two device caveats (monolith is
  120 Hz vsync-capped in most runs; the kernel ignores thread affinity, so the
  client thread runs on a mid core), and the lockstep-feasibility research says
  why the deferred draw barrier waits for P3b/P4b and P11.
- MEASUREMENTS.md section 9: the per-arm table with per-thread CPU ms/frame as
  the primary metric, the interleaved session and the wait/park counters.
- ROADMAP.md: the P5d row is the three-round shape; P11 gains the gPipeInputs
  versioning item the research points at.
- CURRENT_STAGE_PROGRESS.md, README.md, ARCHITECTURE.md (env table: the
  generate_mipmap exception to batched waits, the calibrated spin, the affinity
  readback): head 1f8de61b, the gate numbers and ruling ID-79.
This commit is contained in:
2026-09-18 04:30:38 -04:00
parent 1f8de61be1
commit 2fde70341d
6 changed files with 90 additions and 31 deletions
+3 -3
View File
@@ -605,15 +605,15 @@ CMake:
| `MOBILEGL_TRANSPORT` | `monolith` | `inproc` 已落地;`spawn` / `unix:` / `pipe:` 是 P6,当前具名拒绝并回落 monolith |
| `MOBILEGL_IPC_RING_MB` | 8 | `SEG_CMD`;单条记录至多一半 |
| `MOBILEGL_IPC_STAGE_MB` | 32 | `SEG_STAGE`;目标负载 profile 显式 256 |
| `MOBILEGL_IPC_SPIN_US` | 50 | park 前自旋 |
| `MOBILEGL_IPC_SPIN_US` | 50 | park 前自旋;P5d 三轮起自旋按一次性校准的迭代预算走、稳态不读时钟,`0` = 不自旋直接 park |
| `MOBILEGL_IPC_PERSISTENT_BLOCK_KB` | 64 | persistent-map 推送块粒度;`0` 是 E3(a) 阴性对照 |
| `MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS` | 1 | 推送只发内容变了的块(追踪 buffer 走 mprotect 位图,未追踪走内容哈希);`0` 恢复全范围推送(A/B 对照) |
| `MOBILEGL_IPC_BATCH_WAITS` | 1 | 值类记录(无 reply slot 的 kCtxState/kCtxCso/kCtxObject)发布即返回,barrier 推迟到下一个拉取类 verb;`0` 恢复 R-1 逐条 barrier(`MOBILEGL_PIPE_VERIFY` 强制 0) |
| `MOBILEGL_IPC_BATCH_WAITS` | 1 | 值类记录(无 reply slot 的 kCtxState/kCtxCso/kCtxObject)发布即返回,barrier 推迟到下一个拉取类 verb;**`generate_mipmap` 例外**(它的 apply 读 `MGB_CTX->GetActiveTextureUnit()`,规则:只有 apply 不读残余填充字段的记录才可免等);`0` 恢复 R-1 逐条 barrier(`MOBILEGL_PIPE_VERIFY` 强制 0) |
| `MOBILEGL_IPC_ADOPT_TIER` | 2 | `auto/0/1/2`;P5 split 用 emulated(T2) |
| `MOBILEGL_IPC_VERB_BARRIER` | 1 | 每 verb 等 `appliedSeq == emitSeq`;`0` 只作 E1 阴性对照 |
| `MOBILEGL_IPC_STRICT_ERRORS` | 0 | BARRIER-PULLED residual input 提升为具名 Fatal |
| `MOBILEGL_IPC_AUDIT` | 0 | retire 后 `0xDD` 填退休 staging |
| `MOBILEGL_IPC_SERVER_AFFINITY` | `auto` | apply 线程亲和性 |
| `MOBILEGL_IPC_SERVER_AFFINITY` | `auto` | apply 线程亲和性;日志报告内核实际采纳的掩码(Redmi 的内核对 app 线程一律忽略 `sched_setaffinity`,解析为 0xff) |
| `MOBILEGL_IPC_SERVER_PATH` | 空 | P6 消费 |
P6+ 生效:`MOBILEGL_IPC_PRESENT_CREDIT`、`MOBILEGL_IPC_POLL_ESCALATE`、shadow shm、`MOBILEGL_IPC_RESPAWN`、`MOBILEGL_IPC_IDLE_EXIT_S`。显式不设立:`MOBILEGL_IPC_PROGRAM`(没有 relink 档)、`MOBILEGL_IPC_VALIDATE_SERVER`(server 没有 `MG_Impl` 校验器)。
+8 -2
View File
@@ -1,6 +1,6 @@
# 当前阶段进度
分支 `feat/disaggregated`;代码头 `b88e8487`(2026-09-17,P5c 收官)。本文随每次落地更新。ID-1..75 的逐条裁定长文在 git 历史(`ef35ea0c` 之前版本的本文件)。
分支 `feat/disaggregated`;代码头 `1f8de61b`(2026-09-18,P5d 三轮收官;P5c 收官头 `b88e8487`)。本文随每次落地更新。ID-1..75 的逐条裁定长文在 git 历史(`ef35ea0c` 之前版本的本文件)。
## 1. 阶段状态
@@ -10,13 +10,16 @@
| **P5** 首个 IPC 帧(reduced path,lockstep inproc) | 已收官 | `ff2994d9..37fc4fdb`;`MEASUREMENTS.md` §6 |
| **P5b** inproc 下的 verb 迁移(Minecraft 优先) | **已收官(2026-09-16)** | `37fc4fdb..82683d4a`;`MEASUREMENTS.md` §7 |
| **P5c** `inproc` 共享内存读点归零 | **已收官(2026-09-17)** | `11ac3de6..b88e8487` + triage 修复;契约 `MobileGL/MG_Remote/CONTRACT-P5C.md`;审计 `~/w7/notes/p5c/p5c-audit-v1.md` |
| **P5d** `inproc` 性能专项 | **已收官(2026-09-18,三轮)** | `cb06538c`、`56a77348`、`1f8de61b`;报告 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md);`MEASUREMENTS.md` §9 |
| P6 spawn transport | **下一个** | 届时只是传输替换 |
## 2. 当前头实测
| 门 | 结果 |
|---|---|
| 构建 | pull / push / verify / split 四个 flavour 全部通过 |
| P5d 三轮门(WSL `~/w7/p5d-gate`,split flavour,头 `1f8de61b`) | unit **2203/2203**(tcache_count=0)、`integration-split` **111/111**、两条曾 flaky 用例 `--repeat until-fail:5` 全绿;双生成器 --check/--self-test、include 闭包、dirty-surface、doc 引用全绿;G1 由 CI 核(四包自报 pull 构建零变化) |
| P5d 三轮设备(Redmi,CPU 定频,VD12 世界内 30 s) | inproc p50 **103-106 fps**(起点 64.3),client 线程 CPU 9.2 ms/帧(起点 15.0)、apply 7.0-7.4(起点 12.4);monolith 115(封顶)/ 206(一次未封顶)(此设备 120 Hz vsync 封顶与线程放置不受控,见报告"数字"节) |
| 构建(P5c 收官时) | pull / push / verify / split 四个 flavour 全部通过 |
| G1(pull 符号恒等) | `.text` −16 B,0 增 / 0 删 / **3 认定 resize** / 0 重命名(`SwapchainObject::Create` ev 的表面事件化、`CopyTexSubImage2D` hd 的传输臂、`ScopedRestartIndexSubstitution` 的 server-shadow 臂,均已在合并提交具名);pull 构建零 `MG_Remote` 符号 |
| 发射表分区(`EmitTables.cpp` 的 `static_assert`) | A 2 / B 54 / C 15,共 71 槽(未变) |
| unit | split **2187/2187**(`MOBILEGL_IPC_STRICT_ERRORS=1` 下同绿) |
@@ -81,6 +84,7 @@
## 6. 下一步
0. P5d 的遗留(`P5D-INPROC-PERFORMANCE.md` "什么没完成"):R-1 序列化留给 P3b/P4b → P11(`gPipeInputs` 版本化已写进 P11 行);线程放置记录;小项随 P3b/P4b 顺手。
1. **P6 spawn transport**:`SocketTransport` + `ServerMain` + 握手 / 退出语义 + EGL forwarder 的控制面帧;P5c 之后这只是传输替换。注意 P5c 留下的:`s_synced` / `g_syncedRenderStateParameters` 按 context 世代重置;两个豁免 scope 里的探测在 spawn 下根本不存在对应内存,P6 第一天的红就是它们的清单。
2. 剩余首阻塞一轮(Magma compute/image、rd12、RGB mip、`texture-remint-pull` 仿真槽)。
3. P6 出口门:P5b 的完整渲染路径在 `spawn` 下绿;OpenRA 在 Adreno 830 上 split SSIM ≥ 0.99。
@@ -98,6 +102,7 @@
| P5b 设备证据 | `~/w7/notes/p5b/apk/p5bcodex2/`(APK + proof);`MobileGL/.trace-work/p5b-redmi/p5bcodex2/2f7cbe2e/`(correctness 8/8、`ab-tables.md` 与 bsl 补充表) |
| class-C 普查 | `~/w7/notes/p6/census-classC.md`;基线 `~/w7/p5b-c0b-census-logs/results.json` |
| P5c 审计 | `~/w7/notes/p5c/p5c-audit-v1.md`(59 行清单、wire-clean 清单、与契约的分歧、已有 `rsp` 数字)+ `BRIEF-p5c-audit.md`;Kimi K3 只读静态审计,头 `a79a0af6`,关键行已由集成者逐条抽查 |
| P5d 三轮 | brief `~/w7/notes/p5d/BRIEF-P5D-R3.md`;设备记录 `~/w7/notes/p5d/RESULTS-P5D-R3.md`;四包报告与 lockstep 研究 `~/w7/notes/p5d/reports/`(`E-lockstep-feasibility.md`);profile 数据 `~/w7/notes/p5d/perf/`(`mg-vd12-8`/`mg-mono-1` 为二轮头 `56a77348`);bench 脚本 `~/w7/notes/tools/p5d_bench_*.sh` |
| P5c 契约 / 实测 | `MobileGL/MG_Remote/CONTRACT-P5C.md`(含落地修订);`MEASUREMENTS.md` §8(逐门数字);普查逐名 Fatal 证据 `~/p5c-fatal-map.tsv`;G1 报告 `~/p5c-g1-report.json`;audit 日志 `~/p5c-audit-{bsl,comp}.log` |
| 门日志 | `~/w7/p5-joint-gate.log`、`~/w7/p5b-quickgate.log`、`~/w7/p5-joint-evidence/` |
| 脚本 | `~/w7/notes/tools/`(`wsl_p5_gate.sh`、`p5_ab_redmi.sh`、`p5b_codex_redmi.sh`、`wsl_build_p5_apks.sh`、`p6_census_*.{sh,py}`、`p5b-c0b-census.sh`) |
@@ -123,4 +128,5 @@
| 68 | class-C 普查决定迁移顺序(所有 Minecraft trace 首阻塞 = `DrawElements` → Minecraft 优先) |
| 76 | P5b 出口 = 主机门 `348d22a4` complete + 79 trace 普查 + Redmi 正确性 8/8 + 四臂 A/B |
| 77 | Redmi 钉频期望 1050 → 1100 MHz(2026-09-16);iris-bsl 8 组判为 fixture 123 帧上限,补充表不进 200 帧尾门表 |
| 79 | **P5d 三轮规则(2026-09-18)**:批处理免等只允许 apply 不读残余填充任何字段的记录(`generate_mipmap` 因后端读 `GetActiveTextureUnit` 而必须等);性能诊断以符号化调用图为准、不再从 self% 猜归属;Redmi 上 fps > ~115 的 monolith 数字视为 120 Hz vsync 封顶,配对比较以逐线程 CPU ms/帧为主指标;`sched_setaffinity` / `taskset` 在该内核对 app 线程无效,线程放置只记录 |
| 78 | **P5c 插在 P6 之前**(2026-09-17):`inproc` 先做到两角色之间除 wire 零直接内存访问,P6 只换传输;值类 BARRIER-PULLED 行在 P5c 过线,对象类行留 twin 表阶段;codex 无额度期间只读审计改派 Kimi(K3) |
+29
View File
@@ -447,3 +447,32 @@ splitctl−push 全部在 ±1.6% 内(增量来自 inproc 传输与 barrier,
| 79 trace 普查 | **未重跑**(全集语料不在本机;P5b 的 72/6/1 仍以其头为准) |
审计的 59 处直接访问的终态:纹理纹素 / 形状 / 脏区改读 server staged shadow(tx);反向通道四条事件(ev);句柄解析全部按记录(hd);`applier_reset` / `object_death` 上 wire(ct);值类残余读清零(rv);双层角色守卫 + `InBarrierWait`(gt)。**未到期的具名债**:`MGPipeReverseAnnouncementScope`(绑定记录 P4b 才发射的 ensure/通告族)与 `MGPipeFrontendKeyedRegistryScope`(G6 前端键 twin registry,P3b/P4b 重键)两个 scope 内的只读探测,以及对象类 15 行 BARRIER-PULLED——全部具名、可 grep、有退役阶段。
## 9. P5d(`cb06538c`、`56a77348`、`1f8de61b`;Redmi `2f7cbe2e`,FCL + Minecraft 26.3-rc-3 世界 "test",VD12,DirectGLES)
协议:CPU 定频(大核 1958400 / 小核 1555200,`pin_device.sh`)、风扇二档、世界内 20 s 静置后取 30 s 窗口;fps = `MGPipe stats:` 行的帧数 / 时间(应用侧 swap 计数),逐线程 CPU = `/proc/<pid>/task/*/stat` 的 utime+stime 差 / 帧数。两个已知的不受控变量:GPU 由厂商守护进程在每次启动时把 `min_pwrlevel` 打回 12(inproc 各臂 GPU 都在 342 MHz 空转、CPU 受限,不受影响;monolith 或受 GPU 或 120 Hz vsync 封顶);内核对 app 线程忽略 `sched_setaffinity`,client GL 线程常落在中核(cpu2/4/5)、apply 线程常驻大核 cpu7。因此配对比较以 **client 线程 CPU ms/帧** 为主指标。
| 构建 | 臂 | fps p50 | client ms/帧(核) | apply ms/帧(核) | 备注 |
|---|---|---|---|---|---|
| 二轮头 `56a77348` | inproc | 64.3 | 15.03 (cpu5) | 12.42 (cpu7) | 起点;`SPIN_US=2000` 68-73(三次),`=10000` 63,`SERVER_AFFINITY=off` 65.9 |
| 二轮头 `56a77348` | monolith | 116.5 | 5.85 (cpu7) | — | 75% 忙,vsync 120 Hz 封顶 |
| 三轮审查前构建 | inproc | 114.0 | 8.68 (cpu4) | 6.93 (cpu7) | `SPIN_US=2000` 112.3(不再有收益) |
| 三轮审查前构建 | monolith | 115.7 | 5.70 (cpu5) | — | 封顶 |
| 三轮(本提交) | inproc | 103-106 | 9.2 | 7.0-7.4 | 交错会话,见下 |
| 三轮(本提交) | monolith | 115(封顶)/ 206(一次未封顶) | 5.0-6.2 (cpu7) | — | 三次:115.3 / 115.1(120 Hz 封顶)与 205.8(未封顶) |
交错会话(三轮头,post-review 构建,同一次定频、同一天):
| 臂(顺序) | fps p50 (min / max) | client ms/帧(核) | apply ms/帧(核) | 备注 |
|---|---|---|---|---|
| mono1 | 205.8 (110 / 280) | 5.0 (cpu7) | — | 未封顶的一次;窗口内 110→280 摆动 |
| inproc1 | 106.1 (91 / 112) | 9.24 (cpu4) | 7.0 (cpu7) | |
| mono2 | 115.3 (108 / 117) | 6.2 (cpu7) | — | 120 Hz 封顶 |
| inproc2 | 103.3 (82 / 111) | 9.2 (cpu5) | 7.4 (cpu7) | |
| inproc3 | 101.9 (83 / 109) | 9.1 (cpu5) | 7.3 (cpu7) | |
| mono3 | 115.1 (109 / 117) | 6.1 (cpu7) | — | 封顶 |
审查前构建(同一天早些、机身 50.8 °C 起)inproc 114.0 / client 8.68 ms(cpu4)/ apply 6.93;post-review 构建 pmap 线流量与之逐字节相同(364.7 KB/帧),差在运行间漂移(机身 53-54 °C 起、中核放置)之内。
`wait[]` 计数(三轮加入 stats 行):审查前构建 inproc 30 s 窗口累计 srv=7.56M / srvpark=76k、cli=6.70M / clipark=17k;`SPIN_US=2000` 下 park 各降两个量级、fps 不变——park 已不是主项。持久映射线流量 pmap ≈ 0.36 MB/帧(二轮 0.23,三轮多了首推与脏页排空)。
+46 -22
View File
@@ -1,20 +1,20 @@
# P5d 报告:inproc 性能专项(2026-09-18)
> 状态:**已落地两个提交**(`cb06538c` 一轮、`56a77348` 二轮,均在 `feat/disaggregated` 并已推送)。
> 本报告回答三个问题:要做什么、做到了什么、什么没完成。
> 状态:**三轮,均在 `feat/disaggregated`**——一轮 `cb06538c`、二轮 `56a77348`、三轮 `1f8de61b`(本文所在提交的前一个)。
> 本报告回答三个问题:要做什么、做到了什么、什么没完成。数字表在 §"数字",三轮的设备记录在 `MEASUREMENTS.md` §9。
## 定位与目标
**插入点**:P5c 之后、P6 之前。路线图的既有纪律是"性能对着 pull 臂只记录、不作阻塞门,专门的优化阶段排在路线图推完之后"——但 P5c 收官后在真实负载上的实测把这件事提前了:FCL + Minecraft 26.3-rc-3、视距 12、Redmi `2f7cbe2e`,inproc 世界内只有 **7-13 fps**,monolith 同场景 **~116 fps**,约 9 倍差距,inproc 不可用。
**目标**:在不改变 wire 语义、不动正确性门(双车道、G1/G2/G5/G14、双生成器门)的前提下,把 `inproc` 与 `monolith` 的逐帧帧率差拉到尽可能接近 1。性能数字的采集纪律与其他阶段一致:reboot-clean、同热窗口配对 A/B、只用 Redmi `2f7cbe2e`,设备侧风扇开自动档;A/B 切换靠 `/sdcard/FCL/mg_transport.txt` 运行时开关,免 APK 重编。
**目标**:在不改变 wire 语义、不动正确性门(双车道、G1/G2/G5/G14、双生成器门)的前提下,把 `inproc` 与 `monolith` 的逐帧帧率差拉到尽可能接近 1。性能数字的采集纪律与其他阶段一致:CPU 定频(大核 1958400 / 小核 1555200)、风扇二档、只用 Redmi `2f7cbe2e`;A/B 切换靠 `/sdcard/FCL/mg_transport.txt` 与 `/sdcard/FCL/mg_env.txt`(`MOBILEGL_*` 逐行)两个运行时开关,免 APK 重编。
## 起点的瓶颈链(全部实测,非推测)
- persistent-map 推送:每个 verb 把每个映射的**全范围**推上线(实测 ~25 MB/帧,每 64 KB 块一条记录一次 barrier 往返)。
- 脏检查:每 64 KB 块做内容哈希,**每个 draw 对全部 arena 全范围扫**——XXH64/XXH3 一度占整个进程 73%(绑定过滤后仍 32.8%)。
- barrier:每条 verb 记录一次 `appliedSeq` 往返。
- `Doorbell::Wait` 的自旋每次迭代读一次时钟——该设备上 `clock_gettime` 是真系统调用(无 vDSO),占进程 ~20%。
- `Doorbell::Wait` 的自旋每次迭代读一次时钟(该设备上 vDSO 的 `clock_gettime` 仍占进程 ~20%)。
## 做了什么
@@ -34,33 +34,57 @@
- **零页注册**:子页范围不再落哈希臂,注册为"空内部 + hasEdges"的追踪槽(不保护任何页),全范围由两个有界的边块哈希服务——不再否决任何跳过。
- **shadow 页对齐分配**(`SHADOW_ALLOCATION_ALIGNMENT = 4096`;`GL_MIN_MAP_BUFFER_ALIGNMENT` 查询仍答 64):shadow 占有的每一页字节全是自己的,追踪器永远不必碰邻居分配的字节;边块与零页形态在真实负载中基本消失。monolith 共用该分配器,A/B 无影响。
## 数字(VD12,同场景,in-world 稳定段)
### 三轮(`1f8de61b`,40 文件,+2474/-297):按符号化 profile 逐项切
| 阶段 | split (inproc) | monolith | pmap 线流量/帧 | 关键 profile 行 |
二轮收官报告把 apply 线程 ~48% 的 mutex 时间归给后端 `pendingMutex`,那是猜的。对二轮头 `56a77348` 的 simpleperf 数据(cpu-cycles、整进程、世界内 15 s)符号化后,调用图说的是另一回事,三轮的四个包就按它切:
| 线程 | 热点(self %) | 真因 |
|---|---|---|
| apply | `mutex::lock/unlock` + `pthread_mutex_*` 合计 ~49%,`ApplyThreadMain` 直接调用者占 58-60% | **空转轮询**:`ready` lambda 里的 `ControlIsPending()` 与每圈的 `PumpControlRequest()` 各锁一次 `m_controlMutex`;真正的 `DrainRing` 只占该线程 29% |
| apply | `__emutls_get_address` 7.4%(monolith 渲染线程上 7.7%,是**第一热点**) | `MGPipeFrontendKeyedRegistryScope` / `MGPipeReverseAnnouncementScope` 的 `thread_local` 深度计数器,在 DirectGLES 约 20 个站点(含 `HandleOf` 内)每 draw 多次构造 |
| client | `WaitForApplied` 27.9%(含 34.2%) | R-1 lockstep:每个 draw 等 apply |
| client | persistent-map 推送含 22.5%:`XXH3` 8.5%、`PushBlocksForChecked` 5.6%、`MappedData/IsMapped/GetMappedRange` 2.2% | shadow 分配只对齐了基址、没把**尺寸**补到页倍数,几乎每个 buffer 的映射末尾都不在页界上——**每个 draw 对每个有边的存活映射哈希两块边** |
| client | 时钟读取 6.6%(`steady_clock::now` / `__kernel_clock_gettime` / `clock_gettime`) | `Doorbell::Wait` 每次等待至少读两次时钟;~900 次等待/帧 |
| client | `MGPipeValidateForVerb` 含 10.9%;`OnApplyThread()` 2.66% self;`MarkWritableImageBufferTextures` 3.6% | 残余填充每 verb 对 63 个字段算 7 项合取、每 draw 扫 192 个 image unit;角色守卫 `OnApplyThread` = 函数静态守卫 + 三个原子 + `pthread_equal` |
四个包(每包在自己的 worktree 实现、两视角审查、一轮修复;lockstep 可行性另有一份只读研究):
- **T 传输**:控制邮箱加原子影子位 `m_controlPosted`,空转轮询零锁(邮箱握手、C2 临界区、NOT_INITIALIZED 答复原样);`Doorbell::Wait` 的自旋改为一次性校准的迭代预算,稳态**不读时钟**(park 阶段才算 deadline);client/server 的 wait 与 park 计数进 `MGPipe stats:` 行的 `wait[srv= srvpark= cli= clipark=]` 与 wire ledger 的 `cliwait=/clipark=`。
- **D 角色守卫**:`OnApplyThread()` 内联为"一个 relaxed 原子 key 与调用线程的线程指针比较"(aarch64 走 `__builtin_thread_pointer()`,其余回落 `std::this_thread::get_id()`),删掉 `m_applyThreadId` 与函数静态守卫;三个 scope 深度计数器退掉 `thread_local`——它们唯一的读者是 apply 线程的守卫,所以只在 `OnApplyThread()` 为真时计数(单写者论证写在文件里,并有"GL 线程持有 scope 不豁免 apply 线程"的红一次);守卫链按代价重排。
- **B persistent map**:shadow 分配**尺寸**补到 4096 倍数,`TrackWriteMap` 在 shadow 页粒度可证时**向外**对齐(子页映射 = 一个受保护页),边块与边块哈希在稳态消失;向内臂只作回退。审查抓出一个一轮就存在、被边块哈希掩盖的洞:epoch skip 之前的绑定游走只推消费者,一个 fault 过但本 draw 不消费的映射会被标记为"已消费的 epoch"、之后永不推送——修法是游走前先排空每个有脏页的追踪成员(位图字扫描,稳态零成本),并在注册时推动 epoch 让新映射在 draw 路径上首推一次;`kernel page != 4 KB` 时诚实拒绝 mprotect 臂。
- **C 客户端每 verb**:image unit 高水位(push 构建独有的 `TextureState` 标记,`glBindImageTexture` 喂)替代 192 单元扫;残余填充的 7 项合取按其四个输入 memo 成位掩码;`MGPipeServerStampVerbBoundary` 的 63 字段 per-verb 推导变 constexpr 按 verb 类的掩码表;`ParsePoisonOmissionKnob` 的每 verb 字符串比较改尺寸快路径。
- **两处竞争修复(集成时)**:`generate_mipmap` 目录里是 kCtxObject,但它的 sink 是后端 `GenerateMipmap`,会读 `MGB_CTX->GetActiveTextureUnit()`——批处理下不等 apply,客户端紧接着的 validate 把 serial 与 server stamp 移走,apply 线程读到陈旧输入即 `Fatal{UnmigratedPipeInput, "GetActiveTextureUnit@ReadPixels"}`(F1 的两条 GenerateMipmap 用例在门禁树上复现)。现在它与四个 stamping verb 一样等待;规则写进代码:**只有 apply 不读残余填充任何字段的记录才可以免等**。`TextureDeathCrosses…` 测试补上 FramebufferDeath 已有的围栏(`object_death` 免等,计数只在 apply 时动)。
## 数字(VD12,同场景,世界内稳定 30 s 窗口,CPU 定频、风扇二档)
两个这台设备上不受控的变量,读表前先知道:(1) **monolith 的 fps 大多数运行被 120 Hz vsync 封顶在 ~115**(渲染线程只 66-75% 忙),偶有一次未封顶跑到 206(窗口内 110→280 摆动);inproc 各臂 client 线程 97-99% 忙、GPU 342 MHz 空转,是纯 CPU 受限,fps 可信。(2) 内核对 app 线程忽略 `sched_setaffinity` / `taskset`:split 下常驻自旋的 apply 线程占大核 cpu7,client GL 线程被放到中核(cpu2/4/5,1555 MHz),而 monolith 渲染线程在 cpu7。所以配对比较以**逐线程 CPU ms/帧**为主指标,fps 只作参考。GPU 的 `min_pwrlevel` 每次启动被厂商守护进程打回 12,未能钉住。
| 阶段 | split (inproc) | monolith | client / apply 逐线程 CPU ms/帧 | 关键 profile 行 |
|---|---|---|---|---|
| 起点 | 7-13 fps | ~116 fps | ~25 MB | XXH64/3 73%→32.8%,clock_gettime ~20% |
| 一轮 `cb06538c` | 60-66 fps | 112-115 | ~0.23 MB | WaitForApplied 11.6%,绑定游走 ~8% |
| 二轮 `56a77348` | **63-65 fps** | 110-118 | ~0.23 MB | 绑定游走**消失**,XXH3 2.6%,clock ~2% |
| 起点 | 7-13 fps | ~116 | — | XXH64/3 73%→32.8%,clock_gettime ~20% |
| 一轮 `cb06538c` | 60-66 fps | 112-115 | — | WaitForApplied 11.6%,绑定游走 ~8% |
| 二轮 `56a77348`(当日复测 p50) | **64.3** | 116.5 | 15.03 / 12.42 | 见上表;client 线程被调度在中核(cpu2/4/5),apply 常驻大核 |
| 二轮 + `MOBILEGL_IPC_SPIN_US=2000` | 68-73 | — | 14.0 / 13.6 | park/unpark 是二阶成本;`SPIN_US=10000` 反而 63 |
| 三轮(审查前构建) | **114.0** | 115.7 | 8.68 / 6.93 | `spin2000` 113.0,不再有收益 |
| 三轮(审查后 + 竞争修复,本提交) | 103-106 | 115(封顶)/ 206(一次未封顶) | 9.2 / 7.0-7.4(client 仍在中核) | 复跑 106.1 / 103.3 / 101.9(交错三次) |
帧率比从 ~1:9 收敛到 ~1:1.7。云不闪了(TexBuffer 覆盖),画面与 monolith 无可见差异。
读法:inproc 从 64 → 103-114 fps(+60-77%),client 线程 CPU 从 15.0 → 8.7-9.2 ms/帧(−40%)、apply 线程从 12.4 → 7.0-7.4(其中大半仍是自旋等待)。对着封顶的 monolith(~115)比值 ~1:1.1;对着那次未封顶的 monolith(206,渲染线程 5.0 ms/帧、大核)比值 ~1:2。按 CPU/帧看:inproc 的 client 线程在中核上做 9.2 ms 的活,monolith 渲染线程在大核上做 5.0-6.2 ms——同核折算后 client 侧仍多约 1.2-1.5 倍工作,加上 lockstep 里每 draw 等 apply 的往返,这就是剩余差距的构成。画面与 monolith 无可见差异。
## 验证
- 双车道:unit **2188/2188**、integration-split **111/111** 全绿(期间唯一反复出现的一条红是 `GenerateMipmapDepthPixels` 的环境性 flake:其 DirectGLES/DirectVulkan **monolith** 兄弟变体同样 flaky,而本包全部代码路径在 monolith 下可证明惰性——`PushIsArmed` false、无 ClientSession、deferral 首行 monolith 早退)。
- `gen_pipe.py --check` / `--self-test` 绿,生成文件与生成器一致。
- 每处关键修复都有 red-once 形态的证据:SmallRing SEGFAULT(外向对齐)、GenerateMipmapFieldsCross exit 101(kCtxObject 免等)、CopyImageLayered `Fatal{RoleViolation}`(apply 线程末引用)、余数块计数 3 vs 2(边块未合并)、117 MB/帧(边块无条件推)。
- 三轮门禁(WSL `~/w7/p5d-gate`,split 构建):unit **2203/2203**(tcache_count=0 下)、`integration-split` **111/111**,两条曾 flaky 的用例 `--repeat until-fail:5` 全绿;一/二轮头上 unit 2188、split 111。
- `gen_pipe.py` / `gen_pipe_field_ownership.py` 的 --check/--self-test 绿,include 闭包 0 问题,dirty-surface rc=0,doc 引用 0 问题。
- 每处关键修复都有 red-once 形态的证据(一二轮:SmallRing SEGFAULT、GenerateMipmapFieldsCross exit 101、CopyImageLayered `Fatal{RoleViolation}`、余数块计数、117 MB/帧;三轮:每包报告的 red-once 表——控制影子位的 take-clear 窗口、校准自旋两条、`AThreadCreatedAfterTheLoopStoppedIsNotMistakenForTheApplyThread`、GL 线程 scope 不豁免 apply、子页映射一页保护、fault 过未绑定的映射仍在下一次消费前推送、image unit 高水位两端、残余 memo 重键)。
- 二分定位:四包分别单独上门禁树,`onlyT` 复现 GenerateMipmap abort、`onlyD` 复现 TextureDeath,`onlyB` 全绿——两条都是时序相关的既有竞争(见上),不是包的逻辑错误。
## 什么没完成
1. **后端 sync 锁复合(最大遗留,~18-20% 进程时间)**:apply 线程自身约 **48%** 的时间在 mutex lock/unlock 上——`SyncNeccessaryBuffers` 系路径在每个 draw 对每个 buffer 拿 per-resource `pendingMutex`(外加 `g_poolMutex` / `g_deferredBufferReleasesMutex`),~900 draws/帧放大成毫秒级。monolith profile 里**没有**这个复合(同一份后端代码在单线程下跑)——是锁调用频率 × 流水线序列化的可见性,还是真实竞争,尚未定位到具体站点。这是下一轮的第一目标。
2. **R-1 序列化(`WaitForApplied` ~11%)**:每个 draw 等 `appliedSeq` 的往返。根本解是 `gPipeInputs` 版本化/双缓冲——属于 **P11** 的既定设计范围,本阶段刻意不动。
3. **小项**:`__emutls_get_address` ~3%(emutls 路径上的 thread_local 读);`SetHashSuppressor` 的 XXH3 ~2.6%(P5 遗留的 set 记录去重哈希,另一包的地界)。
4. **验证债**:
- 79-trace 全集本机未跑(无此环境);Redmi 复测窗口未排。
- x86 32 位的 `MGHostSpan` 32B 断言:本包设计是 arm64-only,未做 32 位验证。
- FCL 侧测试接线**未提交**(按约定):`settings.gradle.kts` 的 `:MobileGL` 指向、`FCLauncher.java` 的 renderer env 注入(含 `mg_transport.txt` 开关,该文件在 git 里还处于未解决合并状态 UU,内容正常)、`MobileGL-disagg/build.gradle` 属性映射与 arm64 abiFilters、gradle wrapper 回退 8.13。插件 APK 构建路径里的 `MOBILEGL_TRANSPORT=inproc` 行在打插件包前必须拿掉。
5. **平台可移植性备注**:mprotect+SIGSEGV 臂只覆盖 POSIX(Android/Linux 验证)。Windows 桌面若需要,应加 `GetWriteWatch` 实现臂而非 `#ifdef` 信号路径;哈希臂作为全平台兜底永久保留。handler 已按 JVM 隐式空指针检查的要求链式转发非己 fault。
1. **R-1 序列化仍在**:每个 draw 仍等 `appliedSeq`。只读研究(`~/w7/notes/p5d/reports/E-lockstep-feasibility.md`)的结论是**不要在 P5d 做"draw barrier 延后一个 verb"**:inproc draw 路径上除 `GetBufferBindingSlot` 外每个对象类行都被 server 活读(texture unit 槽的借用指针、UBO 绑定点表、FBO 槽与附件、memo 未命中时的 VAO 属性、program 内部),且身份路径(五张前端键控 twin 表 + `HandleOfBuffer` 经客户端分配器)只能退役不能快照;`GetBufferBindingPoint` 一族根本没有 wire 形式(`set_shader_buffers` 要到 P4b)。真正的路径是 P3b/P4b(按句柄键控的 twin、`set_shader_buffers`)之后的 P11(`gPipeInputs` 版本化)——届时 barrier 延后只是把一处 `WaitForApplied` 搬到下一次 fill 之前。ROADMAP 的 P11 行还没把"`gPipeInputs` 版本化"写进去,本轮补上。
2. **线程放置**:这台内核对 app 线程的 `sched_setaffinity` / `taskset` 一律接受并静默忽略(`MOBILEGL_IPC_SERVER_AFFINITY=auto` 请求 0xc0、解析 0xff),root 下把 GL 线程 tid 写进 `/dev/cpuset/<x>/tasks`(cpus 6-7)也没有改变它的运行核(仍在 cpu5,115 fps / 8.6 ms/帧,在漂移之内);client GL 线程常被放在中核;无法从库内解决,记录。
3. **小项**:`SetHashSuppressor` 的 XXH3(P5 遗留的 set 记录去重哈希);`ReadDrawBindings` 每 draw 重解析 element buffer 句柄;`wants()` 门先读消费者再测脏位(R-8 计数规则未改);两个 `RunsAsTheServerRole` / `OnServerRole` 出线调用为分层保留。
4. **验证债**:79-trace 全集本机未跑;G1 由 CI 的 pull 符号门核(四包自报 0/0/0/0,PipeStats/PipeFill/TextureState 的改动全在 `MOBILEGL_PIPE_PUSH` 或 `MOBILEGL_BUILD_DISAGGREGATED` 之内);x86 32 位的 `MGHostSpan` 32B 断言与 `__builtin_thread_pointer` 的非 aarch64 回落只按检视;FCL 侧测试接线**未提交**(`settings.gradle.kts` 的 `:MobileGL` 指向、`FCLauncher.java` 的 renderer env 注入含 `mg_transport.txt` / `mg_env.txt` 开关、`MobileGL-disagg/build.gradle` 属性映射与 arm64 abiFilters、gradle wrapper 回退 8.13)。插件 APK 构建路径里的 `MOBILEGL_TRANSPORT=inproc` 行在打插件包前必须拿掉。
5. **平台可移植性备注**:mprotect+SIGSEGV 臂只覆盖 POSIX 且要求 4 KB 内核页(16 KB 页内核诚实回落哈希臂——是正确答案但是性能悬崖)。Windows 桌面若需要,应加 `GetWriteWatch` 实现臂而非 `#ifdef` 信号路径;哈希臂作为全平台兜底永久保留。
## 下一轮的入口
按收益排序:后端锁复合(pendingMutex 调用站点定位,先插一次性计数器确认频率,再决定是去锁、合并锁还是改 dirty 探测粒度)→ `SetHashSuppressor` 哈希 → emutls 热点。R-1 序列化不动,等 P11。
P5d 到此收官。剩余项按收益:P3b/P4b 的 twin 表句柄化(同时消掉 apply 线程剩余的 `HandleOf`/emutls 热点与 `HandleOfBuffer` 探针)→ P11 的 `gPipeInputs` 版本化 → barrier 延后。这些都是路线图既有阶段,不再单开性能轮。
+1 -1
View File
@@ -1,6 +1,6 @@
# MGPipe:MobileGL 前后端拆分
> 状态:**P0–P5c 已收官**(2026-09-17,代码头 `b88e8487`)。目标负载(四条 Minecraft A/B trace)已在 Redmi Adreno 830 上以 `inproc`(独立 apply 线程)双后端渲染,barrier tax 首次实测;P5c 把审计出的 59 处不经 wire 的直接内存访问全部归零(契约 `MobileGL/MG_Remote/CONTRACT-P5C.md`),`inproc` 成为只经 wire 交换的诚实两角色。**下一个是 P6 spawn transport**——此时只是传输替换。当前头、逐门数字与开放项见 [`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md)。
> 状态:**P0–P5d 已收官**(P5c 2026-09-17 `b88e8487`;P5d 三轮 2026-09-18,代码头 `1f8de61b`——`inproc` 性能专项,VD12 Minecraft 上 split 从 7-13 fps 拉到 103-106 fps、client 线程 CPU/帧从 15 ms 到 9.2 ms,报告 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md))。目标负载(四条 Minecraft A/B trace)已在 Redmi Adreno 830 上以 `inproc`(独立 apply 线程)双后端渲染,barrier tax 首次实测;P5c 把审计出的 59 处不经 wire 的直接内存访问全部归零(契约 `MobileGL/MG_Remote/CONTRACT-P5C.md`),`inproc` 成为只经 wire 交换的诚实两角色。**下一个是 P6 spawn transport**——此时只是传输替换。当前头、逐门数字与开放项见 [`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md)。
>
> 性能纪律(2026-09-08 起):逐线程 CPU 与 tracker 绝对 ns **对着 pull 臂基线记录**,不作阻塞门;专门的优化阶段排在路线图推完之后。
+3 -3
View File
@@ -1,6 +1,6 @@
# MGPipe 路线图
> 状态:**P0、P0.5、P1、P2、P3a、P4a、P5、P5b、P5c、P5d 已收官**(P5c:2026-09-17,代码头 `b88e8487`;P5d:2026-09-18,代码头 `56a77348`)。当前头、逐门数字、开放项与下一步见 **[`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md)**;设计见 `ARCHITECTURE.md`;逐阶段实测见 `MEASUREMENTS.md`;P5d 报告见 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md)。**下一个是 P6 spawn transport**(此时只是传输替换)。
> 状态:**P0、P0.5、P1、P2、P3a、P4a、P5、P5b、P5c、P5d 已收官**(P5c:2026-09-17,代码头 `b88e8487`;P5d:三轮,2026-09-18,代码头 `1f8de61b`)。当前头、逐门数字、开放项与下一步见 **[`CURRENT_STAGE_PROGRESS.md`](CURRENT_STAGE_PROGRESS.md)**;设计见 `ARCHITECTURE.md`;逐阶段实测见 `MEASUREMENTS.md`;P5d 报告见 [`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md)。**下一个是 P6 spawn transport**(此时只是传输替换)。
## 通用纪律(每个 commit)
@@ -27,14 +27,14 @@
| **P5** 传输 + inproc applier + 发射表 | ✅ `ff2994d9..37fc4fdb` | 同一 codec 上的 `InProcessTransport`;四种 build flavour;发射表三类 / caps mirror / reply mailbox;apply-thread context 终身持有;lockstep verb barrier;tight ReadPixels;persistent-map 块推送;G8 字段归属生成器;split 测试 / CI / APK 车道;八包(c0 契约、w1 codec、s1 session、p1 归属、b1 persistent map、t1 车道、c1 路由、v1 server)+ j0 / x2 / v1-r3 收尾 | joint:OpenRA inproc 2/2 SSIM 1.0;`integration-split` 21/21;E1 14/14 红;G1 0/0/0/0。收尾头全门在 E3(a) 停止(设计性 skip 被判红),Part 2/4 未到达;收官审查 1 blocker / 10 major / 2 minor → P5b r1/r2。§6 |
| **P5b** `inproc` verb migration | ✅ `37fc4fdb..82683d4a` | class-C 普查决定顺序;d1 19 / i1 7 / t2 6 / f1 11 槽迁移;sync 五槽;具名 blit;GLES mip descriptor;r1 / r2;收官审查三项修复。发射表 A=2 / B=54 / C=15 | 主机全门 `348d22a4` complete;`integration-split` 107/107;合并普查零回退、79 trace 72/6/1;**Redmi 正确性 8/8 + 四臂 A/B、barrier tax 首测**。§7 |
| **P5c** `inproc` 共享内存读点归零 | ✅ `11ac3de6..b88e8487` | server 端纹理 staged shadow(`StagedTextureStore`,句柄为键、整段覆盖、defined-ness 追踪);`SEG_EVENT` 三个 producer + `kEventGlError`(反向通道零裸指针);sink / twin 按记录句柄解析(blit 具名臂经 verb 句柄工作区,Magma 走 G6 消费臂);`applier_reset` / `object_death` 控制记录(opcode 77/78,framebuffer 首个 wire delete);`set_context_values`(79)退役全部值类 BARRIER-PULLED 行,三 shutter 自答;双层 `Fatal{RoleViolation}` 守卫 + `InBarrierWait` 接线;两个具名豁免 scope(通告家族 P4b/P7、G6 registry 家族 P3b/P4b)承接未到期的债 | 角色守卫开启下 unit 2187/2187(strict 下同绿)、`integration-split` 111/111、每层守卫 red-once 按名变红;纹理 `0xDD` audit 在 bsl / complementary 两条 in-world trace 零 Fatal;rsp 按帧实测(bsl 948.5/帧,残留全为钉住的对象类 15 行);G1 三个认定 resize(SwapchainObject::Create / CopyTexSubImage2D / ScopedRestartIndexSubstitution,均已具名)+ `.text` −16 B、pull 构建零 MG_Remote 符号;G5 保护区字节一致;双生成器 --check/--self-test 绿 | P5b |
| **P5d** `inproc` 性能专项 | ✅ `cb06538c`、`56a77348` | persistent-map 推送三级臂(mprotect 脏页追踪:SIGSEGV 三重归属判定 + 内收页对齐 + 边块哈希 + 首推全量;哈希抑制 `MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS`;绑定过滤 `PushDrawConsumers` 含 TexBuffer——云闪修复);barrier 批处理 `MOBILEGL_IPC_BATCH_WAITS` + 延期销毁队列 + 两条测试围栏;`Doorbell::Wait` 自旋时钟 64 合 1;零页注册 + shadow 页对齐分配(`SHADOW_ALLOCATION_ALIGNMENT=4096`,GL 查询仍 64);epoch skip 稳态消掉绑定游走 | VD12 Minecraft(Redmi,FCL)split 7-13 → **63-65 fps**,monolith 110-118 同场景(~1:9 → ~1:1.7);pmap 25 MB/帧 → 0.23 MB/帧;unit 2188/2188、`integration-split` 111/111;双生成器绿。未完成:后端 sync 锁复合(apply 线程 ~48% 在锁上)、R-1 序列化(P11)、emutls / set 去重哈希小项。报告:[`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md) | P5b |
| **P5d** `inproc` 性能专项 | ✅ `cb06538c`、`56a77348`、`1f8de61b` | 一二轮:persistent-map 推送三级臂(mprotect 脏页追踪 + 哈希抑制 + 绑定过滤 `PushDrawConsumers`)、barrier 批处理 `MOBILEGL_IPC_BATCH_WAITS` + 延期销毁队列、自旋时钟 64 合 1、零页注册 + shadow 页对齐分配。三轮(按符号化 profile 逐项切,四包 + 一份 lockstep 可行性研究):apply 空转轮询零锁(控制邮箱原子影子位)、`Doorbell::Wait` 校准自旋稳态不读时钟、wait/park 计数进 stats;`OnApplyThread()` 内联为线程指针比较、三个 scope 深度计数器退掉 `thread_local`;shadow 分配尺寸补页、追踪范围向外对齐、边块哈希消失、脏页排空修复;image unit 高水位、残余填充 memo、server stamp 常量表;`generate_mipmap` 不再免等(apply 读残余输入)、death 测试围栏 | 三轮设备(Redmi,CPU 定频):inproc **64.3 → 103-106 fps**(p50),client 线程 CPU 15.0 → 9.2 ms/帧、apply 12.4 → 7.0-7.4;monolith 同场景 115(120 Hz vsync 封顶的运行)/ 206(一次未封顶,渲染线程 5.0 ms/帧 大核);配对比较以逐线程 CPU/帧为主,见报告"数字"节;unit 2203/2203、`integration-split` 111/111(两条曾 flaky 的用例复跑 6/6);双生成器、include 闭包、dirty-surface、doc 引用绿。未完成:R-1 序列化(研究结论:留给 P3b/P4b 后的 P11 `gPipeInputs` 版本化)、线程放置(内核忽略亲和)、`SetHashSuppressor` 哈希等小项。报告:[`P5D-INPROC-PERFORMANCE.md`](P5D-INPROC-PERFORMANCE.md) | P5b |
| **P6** spawn transport | P5c 之后 | `SocketTransport`(socketpair + fork/execve,envp 剔除 + 强制 monolith 双保险);`ServerMain`;`MOBILEGL_IPC_SERVER_PATH` + `dladdr` 兜底;有界重试握手;EOF 即时退出;device-lost latch;EGL forwarder 的控制面帧;P5c 留下的 `s_synced` / `g_syncedRenderStateParameters` 按 context 世代重置 | P5b 的完整渲染路径在 `spawn` 下绿;进程树只多一个子进程;`HeadlessGL` fork 预检无孤儿;OpenRA 在 Adreno 830 上 split SSIM ≥ 0.99 |
| **P3b / P4b** 深化(Espryt) | 待排 | 按存储属主键控的发射游标与 view 索引重映射;`g_fboTextureSyncList`;`ResolvedTextureBindingMemo` / `SamplerPassMemo` / image sweep / program registry 重键;XFB scatter 搬到 client;删 fragColor 重推导 workaround 与 `g_broadcastMemo*`;raw-depth-fetch sampler 原生化;回读 / pack state;P4a 记下的 R-3 / R-4 / R-5 / R-7 / R-10 / R-11;`ProgramArtifacts.h` 的 NDK 尺寸钉 | 纹理 / program 场景;CTS `texture_*` / `shader_image_*` / `packed_pixels` 在 0.5 pp 内;每一个 Iris trace;`TextureUploadShapeScenario` 升级成门 |
| **P7** DirectVulkan(Magma)全量迁移 | 待排 | 其余 10 个子系统:`SetupDrawSnapshot` 探测字段塌成 dirty mask;占位纹理原生化;具名 UBO host payload(D-B8);内部 shader 烘焙;`VertexInputStateFactory` 内容寻址 CSO;D18 容器纪律保留 | 集成 + trace 在 Magma 的 push 与 split 下全绿;verify 零分歧;`nm -D libMobileGLServer.so \| grep glslang` 为空;CTS 0.5 pp 内。**再基线检查点:中点完成子系统 < 40% 立即重定基线** |
| **P8** emulation 下放 + 索引宿主镜像 + 协议广度 | 待排 | `MG_Impl/Pipe/HostResolve.cpp`(client 数组范围、最大索引扫描、`*IndirectCount` 解析,逐站点 reconcile);`Server/IndexHostMirror`;CopyImage 镜像搬到 client;viewport-array 回放验证;`generate_mipmap` 计划 + CPU 回退纹素;大 blob carrier(开放问题 11);无 present fence tick;`kCapDriverOrderedXfbCapture` | `'^DirectGLES\.Split\.'` 与 `'^DirectGLES\.'` 逐名相同;trace split 双后端 SSIM ≥ 0.99 含两个 `coherent_as_flush` fixture;`ClientArrayAfterComputeWriteScenario`;`create-indirect` 上 `roundtrips-per-frame` 读零;`index-mirror-bytes` 逐用例发布 |
| **P9** 反向通道 | 待排 | `SEG_REPLY` 异步 slot 池;PBO 回读 fire-and-forget;`OnGpuWritten` 收窄;`OnBufferWriteback` 批处理 + epoch 排序;`OnXfbScatterReady`;`OnTextureWriteback`;`OnMipLevelsGenerated`;纹理拉取四条缓解 + 终止符;`OnGlError` 有序;`OnSurfaceChanged`;`OnLog` 分级;`SEG_EVENT` 溢出策略;class-C 的 readback 尾 | 回读 / XFB 场景在 split 下绿;`TextureRemintPullScenario`(含无解用例);拉取计数逐 trace 发布;两条故障注入 |
| **P10** sync / query / present 节奏 | 待排 | client 铸造 query handle;轮询入口成门铃点 + `MOBILEGL_IPC_POLL_ESCALATE`;fence 完成度来自逐 fence 退休;非 present fence tick;`present` 1:1;credit 默认 1;roundtrip 计数器与输入延迟直方图;class-C 的 query / swap-interval 尾 | query / XFB / `AsyncCompile` 场景在 split 下绿;trace 上 draw / state / upload 路径 roundtrip 读零;零 timeout 轮询有界退出;配对 A/B 记录 |
| **P11** persistent map 与 ≥16 MiB 采纳 | 待排 | POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial` | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% |
| **P11** persistent map 与 ≥16 MiB 采纳 | 待排 | POST 探针档位选择(T0 主攻,Adreno 可选 T1,T2 回退);`SEG_ADOPT` 生命周期绑 `completedFrameSerial`;**`gPipeInputs` 版本化 / 双缓冲**(P5d 研究:draw barrier 延后一个 verb 的前提,须在 P3b/P4b 的句柄键控 twin 表之后) | `LargeArenaAdoptionScenario` 在所选档下绿;26.3 与两个 Create fixture SSIM ≥ 0.99;Adreno 830 上 p99 帧时与峰值 RSS 对采纳基线(163→21 ms / 40→115 fps / ~400 MB)回归不超过 10% |
| **P12** Android 生产窗口路径 | 待排 | `android:process=":mgl"` Service 收 Java `Surface`;server 生命周期绑 Activity;FCL env 与 plugin APK 开关表接线 | Minecraft 经 FCL 在 spawn 模式下于 Adreno 830 双后端入世界;杀 server 产生干净 device-lost latch |
| **P13** 退役 pull 路径 | 待排 | 删 `SnapshotFromGLContext()` 非 verify 分支、`MGB_CTX`、`MOBILEGL_PIPE_PUSH`、`MOBILEGL_PIPE_LEGACY_MEMOS`;保留 `MOBILEGL_PIPE_VERIFY`;MGPipe recorder;删 `set_residual_value_state`;在计数器活着的情况下重调幸存缓存容量 | `static_assert(sizeof(ResidualValueBlock) == 0)`;三道纯度门在非 verify 构建上转绿;recorder 金标建立;monolith 逐线程 CPU 不差于 P0 基线 |