mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[Docs] (Disaggregated): document the landed P5 inproc milestone
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# MGPipe 设计与架构
|
# MGPipe 设计与架构
|
||||||
|
|
||||||
> 本文描述**已决定**的设计。每条决定附一行理由;数字凡有实测的取实测(见 `MEASUREMENTS.md`)。落地状态以 `feat/disaggregated@458ccde1` 为准:标注"P0 已落地"的是树里的代码,其余是后续阶段要实现的形状(阶段号见 `ROADMAP.md`)。
|
> 本文描述**已决定**的设计。每条决定附一行理由;数字凡有实测的取实测(见 `MEASUREMENTS.md`)。落地状态以 `feat/disaggregated@eec0e836` 为准:P0–P5 已落地;明确标成 P6+ 的仍是后续形状(阶段号见 `ROADMAP.md`)。
|
||||||
|
|
||||||
## 1. 边界
|
## 1. 边界
|
||||||
|
|
||||||
@@ -93,6 +93,8 @@ CSO 在 client 侧内容寻址(Mesa `cso_cache` 先例):每类一张 `ska:
|
|||||||
include 闭包里,而 G1 不允许那里有任何符号位移。`--check` 与 `--self-test`(11 条阴性对照)与
|
include 闭包里,而 G1 不允许那里有任何符号位移。`--check` 与 `--self-test`(11 条阴性对照)与
|
||||||
`gen_pipe.py` 的同样在 CI 里跑。
|
`gen_pipe.py` 的同样在 CI 里跑。
|
||||||
|
|
||||||
|
**G1 的 P5 codegen 陷阱(实测,`c1-v2.md` §9)。** capability gate 若替换的是指针表达式,就必须保留它的**表达式形状**,不能只保留真假值。两个 `if (const auto f = TABLE.GL.Slot)` 被 Bool-valued macro 改写成 block 后,pull `.text` **−144 B**,`GLImpl::GetInteger64v` −150、`GLImpl::GetIntegerv` +2;语义没变,G1 仍正确地判红。落地形状分成 `MGL_BACKEND_SLOT_CAP` 与 pointer-valued `MGL_BACKEND_SLOT_PTR_CAP` / `_PTR_LOCAL`,后者在 pull 展开回原 slot expression。规则不是“宏结果相等”,而是“byte-identical gate 必须保住 init-statement / short-circuit / pointer 的原表达式形状”。
|
||||||
|
|
||||||
### 3.2 分组与计数
|
### 3.2 分组与计数
|
||||||
|
|
||||||
| Class | 条 | 内容 |
|
| Class | 条 | 内容 |
|
||||||
@@ -587,12 +589,44 @@ MobileGL/MG_Remote/ 仅 MOBILEGL_BUILD_DISAGGREGATED
|
|||||||
```
|
```
|
||||||
|
|
||||||
- CMake option(`CMakeLists.txt:23`):`MOBILEGL_BUILD_DISAGGREGATED`(默认 OFF)追加 `MG_Remote/**` 进 `SOURCE_FILES`(`CMakeLists.txt:454-469`)并定义 `-DMOBILEGL_BUILD_DISAGGREGATED=1`;OFF 时 `MG_Config::Transport` 是 `constexpr Monolith`,`Init.cpp` 的分支编译期消失。`3rdparty/flatbuffers/include` 缺失时把 option 强制回 OFF 并 `message(WARNING)`(`CMakeLists.txt:440-451`)。`MobileGL` 与 `MobileGL_s` 都拿到同一份源。`MG_Test/Wire` 只在该 option 下注册(`MobileGL/MG_Test/CMakeLists.txt:93-95`)。
|
- CMake option(`CMakeLists.txt:23`):`MOBILEGL_BUILD_DISAGGREGATED`(默认 OFF)追加 `MG_Remote/**` 进 `SOURCE_FILES`(`CMakeLists.txt:454-469`)并定义 `-DMOBILEGL_BUILD_DISAGGREGATED=1`;OFF 时 `MG_Config::Transport` 是 `constexpr Monolith`,`Init.cpp` 的分支编译期消失。`3rdparty/flatbuffers/include` 缺失时把 option 强制回 OFF 并 `message(WARNING)`(`CMakeLists.txt:440-451`)。`MobileGL` 与 `MobileGL_s` 都拿到同一份源。`MG_Test/Wire` 只在该 option 下注册(`MobileGL/MG_Test/CMakeLists.txt:93-95`)。
|
||||||
- `MOBILEGL_BUILD_DISAGGREGATED_INPROC`(尚不存在):CI/调试形态,隐含开启前者,额外加角色隔离 shim。MGPipe 让需要角色分身的进程全局从四个(`pGLContext`、`gBackendFunctionsTable`、`pActiveBackendObject`、`pDefaultFramebufferInfo`)降到**两个**(pipe 表与 `pActiveBackendObject`):server 角色不再读 `pGLContext`(三道纯度门就是这个断言),`pDefaultFramebufferInfo` 由保留句柄 `{0,1}` + `OnSurfaceChanged` 取代。两个 shim 都不在 GL 热路径的每次访问上——这是 `inproc` 从"成本可疑的实验"变成"可交付形态"的直接原因(Android 上 dlopen 的库无法可靠用 initial-exec TLS,`pGLContext->` 在 `MG_Impl` 有 1494 处)。
|
- `MOBILEGL_BUILD_DISAGGREGATED_INPROC`(P5 已落地):CI/调试形态,隐含开启前者并加角色隔离。MGPipe 让需要角色分身的进程全局从四个(`pGLContext`、`gBackendFunctionsTable`、`pActiveBackendObject`、`pDefaultFramebufferInfo`)降到**两个**(pipe 表与 `pActiveBackendObject`):server 角色不读 `pGLContext`,`pDefaultFramebufferInfo` 由保留句柄 `{0,1}` + surface forwarder 取代。两个角色通过 apply thread 与控制 mailbox 分开,而不是给 1494 个 `pGLContext->` 读点加 TLS。
|
||||||
- `MobileGLServer`:桌面 `add_executable` 链接 `MobileGL_s`;Android `add_executable` 改名 `lib*.so` 链接共享 `MobileGL`,由 AGP 打进 `jniLibs`。
|
- `MobileGLServer`:桌面 `add_executable` 链接 `MobileGL_s`;Android `add_executable` 改名 `lib*.so` 链接共享 `MobileGL`,由 AGP 打进 `jniLibs`。
|
||||||
- `MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>`(P5 起在 `ConfigLoader.cpp` 解析),免费换来 ctest `ENVIRONMENT` 变体、trace-replay 的 `setenv` 块、FCL 用户可编辑 env、plugin APK 的 V2 开关表、`/data/local/tmp` CTS 路径。
|
- `MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>`(P5 起在 `ConfigLoader.cpp` 解析),免费换来 ctest `ENVIRONMENT` 变体、trace-replay 的 `setenv` 块、FCL 用户可编辑 env、plugin APK 的 V2 开关表、`/data/local/tmp` CTS 路径。
|
||||||
- 测试接线陷阱:ctest `ENVIRONMENT` 是替换而非追加、`;` 必须转义、property 覆盖 job env,必须用 `mgl_itest_join_environment(... ${MGL_ITEST_COMMON_ENV})` 构造;`add_trace_replay_test` 加 `SPLIT` 后缀(否则与同 case+backend 重名)并加 `-DTRACE_TRANSPORT=` 给 `run_trace_case.cmake` 消费。
|
- 测试接线陷阱:ctest `ENVIRONMENT` 是替换而非追加、`;` 必须转义、property 覆盖 job env,必须用 `mgl_itest_join_environment(... ${MGL_ITEST_COMMON_ENV})` 构造;`add_trace_replay_test` 加 `SPLIT` 后缀(否则与同 case+backend 重名)并加 `-DTRACE_TRANSPORT=` 给 `run_trace_case.cmake` 消费。
|
||||||
- CI(`.github/workflows/test.yml:1538` `pipe-gates`,P0 已落地):`gen_pipe.py` 重生成 + diff;`MG_Backend`/`MG_State` 下禁止 stdio 插桩的 grep 门;`gen_pipe_dirty_surface.py --check` + `--self-test`(**P2 起成为门**,`.github/workflows/test.yml:1601-1604`,取代原来信息性的 `--summary` 步骤);`check_doc_citations.py`(警告级,文档定稿后 `--strict`)。独立 job `flatc-check`。已落地:`include-graph-check`(P0.5)、`monolith-symbol-report`、`build-linux-verify` / `integration-verify` / `retrace-verify`(P1)。
|
- CI(`.github/workflows/test.yml:1538` `pipe-gates`,P0 已落地):`gen_pipe.py` 重生成 + diff;`MG_Backend`/`MG_State` 下禁止 stdio 插桩的 grep 门;`gen_pipe_dirty_surface.py --check` + `--self-test`(**P2 起成为门**,`.github/workflows/test.yml:1601-1604`,取代原来信息性的 `--summary` 步骤);`check_doc_citations.py`(警告级,文档定稿后 `--strict`)。独立 job `flatc-check`。已落地:`include-graph-check`(P0.5)、`monolith-symbol-report`、`build-linux-verify` / `integration-verify` / `retrace-verify`(P1)。
|
||||||
|
|
||||||
|
## 17. P5 落地形状:lockstep `inproc`、reply 与 apply-thread server
|
||||||
|
|
||||||
|
### 17.1 verb barrier 与诚实的同地址空间传输
|
||||||
|
|
||||||
|
P5 的 `inproc` 是真第二线程,但还是 **lockstep**:每条 class-B verb 发射后,client 的 `EmitAndWait` 等到 `appliedSeq == emitSeq`;`MOBILEGL_IPC_VERB_BARRIER=1` 默认开启。理由不是吞吐,而是 27 个 BARRIER-PULLED 字段尚无记录载体;在这些字段退役前让两线程同时跑,会让 server 读到 client 的“未来值”(R-1,ID-4)。barrier 是逐族可退役对象,不是 P6 transport 的要求。
|
||||||
|
|
||||||
|
同一地址空间不得成为旁路(R-2):encoder 把 `MGHostSpan::Ptr` 恒写成 `nullptr`,内容 blob 必须带真实 `SEG_STAGE` / 段内 offset / 非零 size;decoder 对四种形状分别 `Fatal{ProtocolCorruption}`——非空 `Ptr`、内容记录 size 为 0、非零 size 却无 segment、`offset+size` 越界。`MapPersistent` 在 split 恒 decline;`MOBILEGL_IPC_AUDIT=1` 在 retire 后把 staging 填 `0xDD`,让跨 applier 返回持针的实现下一次读取时可见地失败。四个 Fatal 与 audit 使 `inproc` 和未来 spawn 表达同一份所有权。
|
||||||
|
|
||||||
|
reply mailbox 以**记录序号作为 slot id**(R-3):slot header 是 `{Seq, Status, Size}`,acceptance 的四个 Bool 答案与 `MapPersistent` decline 都在既有 verb wait 内读取,不增加第二次等待。`Status=ERROR` 一律 `Fatal{ReplyError}`,不能退化成 false;读到 reply 之前先由 `appliedSeq` 证明该记录已离开 applier(R-5)。P9 才把这套同步 mailbox 推广成异步池。
|
||||||
|
|
||||||
|
### 17.2 71 槽的路由、caps 与 tight readback
|
||||||
|
|
||||||
|
client 表只有三类(`CONTRACT-P5.md` §7):2 个 getter 从 caps mirror 本地回答;5 个 P5 verb 发射;其余 64 个 `Fatal{UnmigratedVerb}`。实现不是手写 switch:**33 条**走 generated route tables,**4 条 escape** 保留专用 reply/资源语义,`PipeCatalogueTest` 同时钉住 **37**。R-17 的第一轮只替换 `MGPipeApply<Name>(` 调用表达式,漏掉了五个 `&MGPipeApply<Name>` 地址获取点,四条 delete/resource row 于是仍在 GL thread 同步执行;落地门因此既扫调用也扫 address-of。教训:生成路由的完备性必须覆盖值调用与函数地址,两者不是同一张 grep 表(ID-58/61)。
|
||||||
|
|
||||||
|
能力存活只读 `CapsMirror` 中的 `MGPCaps::CallMask`;server 的 consumer mask 由 backend 类型显式设置并以实际 op table 校验,**永不**从进程级 `MGPipeGetResourceOps()` 推导。41 个旧 slot-null probe 也改读对应 cap,否则 non-null emit table 会把所有 fallback 错判成“支持”(R-8)。成功的 `MakeEGLCurrent` / `InitCapabilities` 重新发布 snapshot;client 按 generation 采纳(R-12)。
|
||||||
|
|
||||||
|
`ReadPixels` 在线上恒为 **tight**:server 临时设 neutral pack(row length / skips = 0,alignment = 1),只向 reply 写 `width*height*bytesPerPixel`;client 用自己持有的 pack state scatter,row gap 保持原字节(ID-49)。绑定 PACK PBO 时 P5 在 client 侧、发射和解引用之前 `Fatal{UnmigratedVerb, "ReadPixels+PACK_BUFFER"}`;server 直接写 buffer resource 并 `MarkGpuWritten` 是 P6+ 的真实形状(ID-57)。reply 单槽 payload 上限是 `2 MiB - 16`,更大 readback 的 carrier 同样留给 P6+。
|
||||||
|
|
||||||
|
### 17.3 server 角色、shadow 与退出
|
||||||
|
|
||||||
|
`ServerLoop` 的 `mgl-srv-apply` 是 native context 的终身 owner。`ServerMakeEGLCurrent` 对 `(dpy, draw, read, ctx)` tuple **只 bind 一次**;相同 tuple 是 no-op,client release 只记账、绝不让 apply thread native-unbind,context 直到 destroy / context loss 才离开该线程(ID-54)。罕见 EGL 操作经 caller-serialised one-slot control mailbox 进 apply thread;十二个 `Server*` forwarder 是唯一缝,其中 make-current 与 init-caps 成功时执行 R-12 republish。mailbox 在 stop 判定与 publish 上共用 mutex;有 backend 却无 thread 时 `Fatal{ApplyThreadNotRunning}`,不允许回落到 app thread。
|
||||||
|
|
||||||
|
`PipeApplier::ApplyOne` 依次 stamp verb、decode/apply、清 stamp;只有 `SessionConsumer::ApplyOne` 每条记录把 `appliedSeq` 加一,pad 不计数。五条没有 `MGPipeApply*` 的 class-B verb 由 `ServerVerbSink` 消费。`StagedShadowStore` 按 resource twin 复制并合并**精确覆盖范围**;`Ops_H_SubData` / flush / respecify 只把 server-owned copy 交给后端,任何 widened read 先过 `RequireStagedCoverageForPendingRanges`,否则 `Fatal{StageSnapshotTooNarrow}`(R-11)。
|
||||||
|
|
||||||
|
退出顺序承重:`ShutdownSplitRoles` 先让 client publish 并 bounded-drain,再 shutdown transport / 唤醒 wait,随后 bounded-join apply thread;线程在仍持 context 时 detach decoder、销毁 private backend,最后才销毁 emitter 与 transport。这样 stats dump、`pActiveBackendObject.reset()` 与 ring unmap 都发生在 thread 退出之后。
|
||||||
|
|
||||||
|
### 17.4 lane 隔离、G5 与阶段边界
|
||||||
|
|
||||||
|
每条 `DirectGLES.Split.*` entry 有独立 `MOBILEGL_LOG_FILE_PATH`;E1/E3 控制从被选 entry 的私有文件取 Fatal,不能从并行 lane 的公共日志“借红”(ID-53)。G5 的第十一行 `FlushPendingRangesFrom` 因 P5 的 range 参数化被承认,但两份 untouched-region script 都**始终**对固定 pin `172b0222…` 比较;re-pin 必须同时改两份脚本,不能让 ref-a/ref-b 漂移掩掉改变(ID-41)。
|
||||||
|
|
||||||
|
P5 到此只声称 reduced path:private lane、barrier、reply、shadow 与 context ownership 已落地;class-C verb、27 个 readback/query wrong-answer、`rsp` residual inputs、PACK-PBO 真 carrier、>2 MiB readback、GetCaps 的两个 server→client blob carrier 与 ABI fingerprint 的 segment-size 混入都属于 P6+ / P7 / P3b-P4b,逐项见 `ROADMAP.md`,不由 `inproc` 同地址空间替它们背书。
|
||||||
|
|
||||||
## 附 A:开关
|
## 附 A:开关
|
||||||
|
|
||||||
CMake:
|
CMake:
|
||||||
@@ -601,7 +635,7 @@ CMake:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `MOBILEGL_BUILD_DISAGGREGATED` | OFF | 已落地 |
|
| `MOBILEGL_BUILD_DISAGGREGATED` | OFF | 已落地 |
|
||||||
| `MOBILEGL_BUILD_SERVER_SPIKE` | OFF(仅 Android) | 已落地(spike A,非出货) |
|
| `MOBILEGL_BUILD_SERVER_SPIKE` | OFF(仅 Android) | 已落地(spike A,非出货) |
|
||||||
| `MOBILEGL_BUILD_DISAGGREGATED_INPROC` | OFF | 计划(P5) |
|
| `MOBILEGL_BUILD_DISAGGREGATED_INPROC` | OFF | 已落地(P5) |
|
||||||
| `MOBILEGL_PIPE_VERIFY` | OFF | 计划(P1;构建期开关,编译进 `SnapshotFromGLContext()` 与 G4 比对器,P13 后保留) |
|
| `MOBILEGL_PIPE_VERIFY` | OFF | 计划(P1;构建期开关,编译进 `SnapshotFromGLContext()` 与 G4 比对器,P13 后保留) |
|
||||||
| `MOBILEGL_PIPE_LEGACY_MEMOS` | ON(P2..P13) | 已落地(P2;`CMakeLists.txt:36`,OFF 时不编译 pre-handle 臂;`MOBILEGL_PIPE_PUSH=OFF` 会把它强制回 ON 并 `message(STATUS)`,`CMakeLists.txt:476-479`,因为 pull 构建里 pre-handle 臂就是唯一的实现) |
|
| `MOBILEGL_PIPE_LEGACY_MEMOS` | ON(P2..P13) | 已落地(P2;`CMakeLists.txt:36`,OFF 时不编译 pre-handle 臂;`MOBILEGL_PIPE_PUSH=OFF` 会把它强制回 ON 并 `message(STATUS)`,`CMakeLists.txt:476-479`,因为 pull 构建里 pre-handle 臂就是唯一的实现) |
|
||||||
| `MOBILEGL_FLATC_EXECUTABLE` | 空 | 已落地(只服务 `flatc-check`) |
|
| `MOBILEGL_FLATC_EXECUTABLE` | 空 | 已落地(只服务 `flatc-check`) |
|
||||||
@@ -621,7 +655,7 @@ CMake:
|
|||||||
| `MOBILEGL_PIPE_STATS_PERIOD` | 120(1–10⁶) | 每多少帧一条汇总行 |
|
| `MOBILEGL_PIPE_STATS_PERIOD` | 120(1–10⁶) | 每多少帧一条汇总行 |
|
||||||
| `MOBILEGL_PIPE_STATS_FILE` | 空 | teardown 时的 JSON 转储路径 |
|
| `MOBILEGL_PIPE_STATS_FILE` | 空 | teardown 时的 JSON 转储路径 |
|
||||||
|
|
||||||
运行时,传输与 IPC(计划,P5+):`MOBILEGL_TRANSPORT`(monolith)、`MOBILEGL_IPC_SERVER_PATH`、`MOBILEGL_IPC_RING_MB`(8)、`MOBILEGL_IPC_STAGE_MB`(32)、`MOBILEGL_IPC_PRESENT_CREDIT`(1)、`MOBILEGL_IPC_SPIN_US`(50)、`MOBILEGL_IPC_POLL_ESCALATE`(64)、`MOBILEGL_IPC_PERSISTENT_BLOCK_KB`(64)、`MOBILEGL_IPC_ADOPT_TIER`(auto)、`MOBILEGL_IPC_SHADOW_SHM`(1,Phase 2 起)、`MOBILEGL_IPC_INLINE_PAYLOADS`(0,负面对照)、`MOBILEGL_IPC_SERVER_AFFINITY`(auto)、`MOBILEGL_IPC_STRICT_ERRORS`(0)、`MOBILEGL_IPC_AUDIT`(0)、`MOBILEGL_IPC_TRACE`(0)、`MOBILEGL_IPC_ATTACH`、`MOBILEGL_IPC_RESPAWN`(0)、`MOBILEGL_IPC_IDLE_EXIT_S`(30)。显式不设立:`MOBILEGL_IPC_PROGRAM`(没有 relink 档)、`MOBILEGL_IPC_VALIDATE_SERVER`(server 没有 `MG_Impl` 校验器)。既有负面对照开关(`MOBILEGL_ESPRYT_DISABLE_{UBO,UNPACK,UPLOAD}_RING`、`_INVALIDATE_FLUSH`、`MOBILEGL_DISABLE_LARGE_BUFFER_ADOPTION`、`MOBILEGL_COHERENT_AS_FLUSH`)全部保留。
|
运行时,传输与 IPC(P5 已落地的核心项):`MOBILEGL_TRANSPORT`(monolith)、`MOBILEGL_IPC_VERB_BARRIER`(1)、`MOBILEGL_IPC_RING_MB`(8)、`MOBILEGL_IPC_STAGE_MB`(32)、`MOBILEGL_IPC_PERSISTENT_BLOCK_KB`(64)、`MOBILEGL_IPC_ADOPT_TIER`(2)、`MOBILEGL_IPC_STRICT_ERRORS`(0)、`MOBILEGL_IPC_AUDIT`(0)、`MOBILEGL_IPC_SERVER_AFFINITY`(auto)。`MOBILEGL_IPC_SERVER_PATH`、present credit、poll escalation、shadow shm、attach/respawn/idle-exit 等随 P6+ 生效。显式不设立:`MOBILEGL_IPC_PROGRAM`(没有 relink 档)、`MOBILEGL_IPC_VALIDATE_SERVER`(server 没有 `MG_Impl` 校验器)。既有负面对照开关全部保留。
|
||||||
|
|
||||||
## 附 B:边界计数器(`MobileGL/MG_Util/Metrics/PipeStats.h:46-122`,P0 已落地)
|
## 附 B:边界计数器(`MobileGL/MG_Util/Metrics/PipeStats.h:46-122`,P0 已落地)
|
||||||
|
|
||||||
|
|||||||
@@ -632,3 +632,106 @@ P4a 的契约改了七次(`c0b`…`c0g`),外加一轮缝类审计与一轮
|
|||||||
`mc_vanilla_draw` 上:**espryt T1(`0x1fff` − pull)= +1076.1 ns/draw,T2(`0x1ff` − pull)= +1064.7,T1 − T2 = +11.4**;magma T1 = +629.0、T2 = +452.6、T1 − T2 = +176.4。blend toggle:espryt +964.5 / magma +738.9 ns per toggle pair;pass switch:espryt +8766.9、magma −4555.7(后者符号为负,属该项的噪声量级)。
|
`mc_vanilla_draw` 上:**espryt T1(`0x1fff` − pull)= +1076.1 ns/draw,T2(`0x1ff` − pull)= +1064.7,T1 − T2 = +11.4**;magma T1 = +629.0、T2 = +452.6、T1 − T2 = +176.4。blend toggle:espryt +964.5 / magma +738.9 ns per toggle pair;pass switch:espryt +8766.9、magma −4555.7(后者符号为负,属该项的噪声量级)。
|
||||||
|
|
||||||
**桌面这台机上,"P4a 自己"落在本 bench 的噪声底以下,所以不要单独引用它。** 同一份脚本在 `6035c9d7`(终审修复前)上跑出的是 espryt T1 +1269.7 / T2 +1135.8 / **T1 − T2 = +133.9**,本轮是 +1076.1 / +1064.7 / **+11.4**——**两臂的绝对值在两轮之间各自漂了 ~200 ns,而它们的差只有 10–130 ns**,也就是说这个 bench 分辨不出 P4a 这一档的增量。真正可引用的是:(1) **T1 ≈ +1.1 µs/draw 的总边界**(对 pull 基线,Espryt;这条在两轮之间是稳的);(2) **设备侧的三臂表(§24)**——那里 P4a 自己是 +3.4 ~ +5.7 个百分点、0.05–0.38 ms/帧,样本全部在验证过的定频窗口里。**Magma 的 T1 − T2 = +176.4 ns 不是"Magma 在跑 P4a"**:c0f 的消费者门让它一条 P4a 记录都不发(设备侧 §24 的 Magma 两臂差也在噪声内),这 176 ns 是 tracker 多算的那几个快门加噪声。
|
**桌面这台机上,"P4a 自己"落在本 bench 的噪声底以下,所以不要单独引用它。** 同一份脚本在 `6035c9d7`(终审修复前)上跑出的是 espryt T1 +1269.7 / T2 +1135.8 / **T1 − T2 = +133.9**,本轮是 +1076.1 / +1064.7 / **+11.4**——**两臂的绝对值在两轮之间各自漂了 ~200 ns,而它们的差只有 10–130 ns**,也就是说这个 bench 分辨不出 P4a 这一档的增量。真正可引用的是:(1) **T1 ≈ +1.1 µs/draw 的总边界**(对 pull 基线,Espryt;这条在两轮之间是稳的);(2) **设备侧的三臂表(§24)**——那里 P4a 自己是 +3.4 ~ +5.7 个百分点、0.05–0.38 ms/帧,样本全部在验证过的定频窗口里。**Magma 的 T1 − T2 = +176.4 ns 不是"Magma 在跑 P4a"**:c0f 的消费者门让它一条 P4a 记录都不发(设备侧 §24 的 Magma 两臂差也在噪声内),这 176 ns 是 tracker 多算的那几个快门加噪声。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 26. P5 五部分门(joint `e61d0012`)与 landed quick gate(`eec0e836`)
|
||||||
|
|
||||||
|
P5 的完整记录来自 `~/w7/notes/p5/p5-results/joint-v1.md` §2 与 ID-63;脚本按 **1 → 5 → 3 → 2 → 4** 的顺序跑。`e61d0012` 是 joint scratch head,随后同一组 landed 代码进入 `feat/disaggregated@eec0e836`;landing 后按 ID-66 只跑 quick gate,不把 quick gate 写成第二次 full gate。
|
||||||
|
|
||||||
|
| 部分 | joint 实测 |
|
||||||
|
|---|---|
|
||||||
|
| **1 接口纯度** | include closure **4 probes / 0 problems**;pull `MG_Remote` symbol **0**、split **610**;G1 `.text` **10806611 → 10806611**、defined symbols **27814 → 27814**、**0 added / 0 removed / 0 resized / 0 renamed**;P3a/P4a G5 对 `ff2994d9` byte-identical |
|
||||||
|
| **5 coverage / generator** | `gen_pipe` up-to-date、self-test **9/9**;dirty-surface **27/27**(`UseProgram` 一项明确为 UNDECIDED,不伪装成 absence proof);field ownership up-to-date、**15/15**;emitter/CSO **185/185**;verify controls **4/4** |
|
||||||
|
| **3 行为 A/B** | G2 name diff **0**;G14 **0 removed / 42 added**;unit **1816/1816 ×3**、split **2038/2038**;Wire **58/58**;integration-gpu pull **1128/1128**、push **1128/1128**、split-monolith **1149/1149**;split-inproc **426 pass / 185 skip / 511 abort / 27 fail / 0 segfault**;`integration-split` **21/21(19 run、2 design-skip)**;persistent arm **2/2**,split `pmap=2160.00, mpr=1`,push `pmap=0.00, mpr=1` |
|
||||||
|
| **2 语义 / retrace** | integration-verify **930/930**、`Fatal{` **0**;OpenRA inproc **2/2**、两后端 SSIM **1.0**、`Fatal{` **0**;push retrace **79/79**;verify retrace **79/79**、armed **79/79**、`Fatal{` **0** |
|
||||||
|
| **4 设备** | **未跑**;joint package 明确禁止 adb。设备 A/B 留在 §30,不用 desktop 数代填 |
|
||||||
|
|
||||||
|
landed quick gate(ID-66):split unit **2038/2038**;`integration-split` inproc **22/22**(比 joint 多 `SplitLogPaths`);push integration-gpu **1128/1128**;G1 **0/0/0/0、`.text +0`**。这组数证明 landing 没丢 joint 的 reduced path,不声称重跑了 Part 2/4。
|
||||||
|
|
||||||
|
## 27. P5 退出门 E1–E6:门、阴性控制与处置
|
||||||
|
|
||||||
|
| 门 | 实测与“为什么会红” |
|
||||||
|
|---|---|
|
||||||
|
| **E1 barrier** | default reduced path 三次均 **19 pass / 2 skip / 0 fail**;`MOBILEGL_IPC_VERB_BARRIER=0` 选中的 **14/14** 全 abort,且每个 private lane file 都有自己的 `Fatal{BarrierViolation, "<slot>"}`(ID-53/65,`joint-v1.md` §3) |
|
||||||
|
| **E2 OpenRA** | baseline **2/2、SSIM 1.0**;pull library + `inproc` 的 transport control 会红。`MOBILEGL_IPC_E2_DROP_CLEAR=1` 已武装但仍 **1/1、SSIM 1.0、mismatchPixels=0**,所以 clear-drop 控制**没有**因自己的理由变红,pending x2;不能据此反推 wire bypass(ID-65) |
|
||||||
|
| **E3 persistent map** | (a) block KB=0:**6 selected / 4 red / 2 skip**,红在第二次无 GL 宣告写的 pixel assertion;(b) 该无宣告写在场景内;ID-42 的 emulated membership 经 green → `return false` **3 red** → restored green,已 VERIFIED;(c) counting lane `pmap=2160.00 / mpr=1`,push `0.00 / 1`;(d) split apply 恒 decline,不返回 host pointer;(e) SmallRing entry 跑过,但无 wrap/wait counter,pending x2(ID-42/63/65) |
|
||||||
|
| **E4 field ownership** | generator **15/15** own-message controls;strict lane **19 abort / 2 skip / 0 pass**,首条具名 `Fatal{UnmigratedPipeInput, "GetTextureContextId@Clear"}`。这是 BARRIER-PULLED 债务的响亮读法,不是 default regression(ID-65) |
|
||||||
|
| **E5 honest inproc** | `MOBILEGL_IPC_AUDIT=1`:**19 pass / 2 skip / 0 fail**;production SubData copy 与 `0xDD` poison 两条 shipped test 通过。五条机制已在代码门上覆盖,但“corrupt staged upload 再 draw”这个 R-16 半边未执行,**pending v1 round 3**,不把 audit-green 扩写成它已自证(ID-65) |
|
||||||
|
| **E6 phase gate** | G1 **0/0/0/0**、G2 name diff **0**、G14 **0 removed / 42 added**;verify **930/930**;push/verify retrace **79/79**。broad inproc census是 **426/185/511/27/0**,其 attribution 如下;reduced path 与记录债务分开结算(ID-63/65) |
|
||||||
|
|
||||||
|
E6 的 27 个普通失败逐条复跑均 `rc=1`、private log **0 Fatal**;8 个争议项又各跑三次,无 flake。归属不是从测试名猜的,而是 `joint-v1.md` §4 的 probe:
|
||||||
|
|
||||||
|
| family | 条 | 记录去向 |
|
||||||
|
|---|---:|---|
|
||||||
|
| `LayeredAttachmentShapeScenario` | 14 | P4b/P7 layered texture readback |
|
||||||
|
| packed depth/stencil `GetTexImage` | 3 | P4b/P7 texture-shadow readback |
|
||||||
|
| framebuffer `HandleRecycleScenario` | 5 | P4b/P7 readback;不是已证明的 handle recycle bug |
|
||||||
|
| `PrimitivesGeneratedNoXfbScenario` | 3 | P7 query / primitive accounting |
|
||||||
|
| `TextureParamsWithoutASamplerView` | 1 | P6 shared-backend inspection forwarder |
|
||||||
|
| `P4aFinalFixScenario` FBO/RBO delete | 1 | P6 shared-backend lifetime after transported delete |
|
||||||
|
|
||||||
|
511 个 abort 只**计数**,没有逐条诊断;抽样两条分别是 `DrawElements` 与 `BeginTransformFeedback` 的 class-C `Fatal{UnmigratedVerb}`。因此“511 全是 class C”不作为测量结论(`joint-v1.md` §4)。
|
||||||
|
|
||||||
|
## 28. R-10、逐帧 ledger 与内存口径
|
||||||
|
|
||||||
|
`joint-v1.md` §5 在 `MOBILEGL_PIPE_STATS_PERIOD=1` 下只取真实非零窗口:
|
||||||
|
|
||||||
|
| entry | frame/window | `pmap` bytes/frame | `mpr` | `rsp` |
|
||||||
|
|---|---|---:|---:|---:|
|
||||||
|
| Triangle redraw | 1/1 | 0.00 | 0 | 35 |
|
||||||
|
| Triangle redraw | 2/1 | 0.00 | 0 | 35 |
|
||||||
|
| Persistent map write-after-frame | 1/1 | 600.00 | 1 | 35 |
|
||||||
|
| Persistent map write-after-frame | 2/1 | 600.00 | 0 | 35 |
|
||||||
|
|
||||||
|
| entry | server accept peak RSS | client handshake peak RSS | client teardown peak RSS |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| Triangle | 11,526,144 B | 11,706,368 B | 141,451,264 B |
|
||||||
|
| Persistent map | 11,464,704 B | 11,649,024 B | 141,422,592 B |
|
||||||
|
|
||||||
|
`inproc` 两角色共享一个进程,所以上表是**进程**峰值,不是两个独立 physical peak;server 只在 accept 时取样,不能声称 full-run server peak,也没有 N-frame RSS slope。日志另报 `roleMapped=58,990,592 B`、`allRolesMapped=117,981,184 B`。规范 ledger 由执行过的 `ProtocolSmokeTest` 钉住:**SEG_CMD 8 MiB / SEG_STAGE 32 MiB / SEG_REPLY 16 MiB / SEG_EVENT 256 KiB**(ID-47/65)。
|
||||||
|
|
||||||
|
**max record bytes:没有场景测量,pending x2。** encoder 有 `MaxRecordBytesSeen`,但 scenario telemetry 未发布;单元只证明它远小于 half-ring,不提供这两个场景的数。这里不从 struct size 或 ring capacity 反推(`joint-v1.md` §5)。
|
||||||
|
|
||||||
|
## 29. 复审作为过程测量:跨族发现、轮次与身份修复
|
||||||
|
|
||||||
|
wave-1 跨模型族复审的十项全部经独立 perturbation **CONFIRMED(10/10,0 refuted,0 partial)**;它量到的不是“代码行多”,而是十个本轮同族门没有捕获的具体缝(ID-46/48,`wave1-codex-review.md` + `wave1-codex-verify.md`):
|
||||||
|
|
||||||
|
| # | confirmed finding |
|
||||||
|
|---:|---|
|
||||||
|
| 1 | empty `SEG_STAGE` wrap arithmetic 拒绝本可容纳的 blob |
|
||||||
|
| 2 | 旧 8-slot reply geometry 连 512×512 RGBA8 都差 16 B |
|
||||||
|
| 3 | blob validation 接受任意 mapped segment,audit poison 覆盖不全 |
|
||||||
|
| 4 | wire `MapPersistent` decline 绕过 adoption-tier refusal |
|
||||||
|
| 5 | pad-bit control 经 `Reserve` 后根本没有发送该 bit |
|
||||||
|
| 6 | ABI sensitivity gate 驱动的是 production 已不调用的 helper |
|
||||||
|
| 7 | null-union control 没到达 handshake guard |
|
||||||
|
| 8 | 三个 CI negative control 接受任意非零退出 |
|
||||||
|
| 9 | `gen_pipe.py expect_trip` 接受任意 `SystemExit` |
|
||||||
|
| 10 | 两个 death control 使用空 diagnostic regex |
|
||||||
|
|
||||||
|
后续 v1/c1 review 的数量本身也入账,作为门质量的过程数据:
|
||||||
|
|
||||||
|
| 决策 | review 读数 | 处置 |
|
||||||
|
|---|---|---|
|
||||||
|
| ID-52(v1 两审合并) | cross-family **2 blockers + 8 majors + 1 minor**;same-family 另给 M-1..M-7、m-1..m-7,五个 codex-only 项先执行验证 | confirmed set 进入 v1 round 2 |
|
||||||
|
| ID-58(c1 round 2) | **3 blockers / 8 majors / 6 minors** | round 3;若仍有 blocker 才拆包 |
|
||||||
|
| ID-62(v1 round-2 review) | **7 closed / 7 partial / 1 not closed**,新增 **5 majors** | round 3;E1 skip-false-green 转 j0 |
|
||||||
|
| ID-64(c1 round-3 review) | **8 closed / 6 partial / 1 not closed**,新增 **0 blockers / 5 majors / 4 minors** | 判 MERGEABLE;剩余 gate debt 转 c1f |
|
||||||
|
|
||||||
|
这些数字解释了流程为何在 P5 尾声改变:用户要求不再在轮次中做过度验证;以后 package 自门 + quick gate 落地,每阶段末只做一次 Codex adversarial review,发现进入下一阶段首轮(ID-66)。
|
||||||
|
|
||||||
|
另一个过程事实是 identity rewrite(ID-40):Sep 8 以后 WSL repo-local `rereview <rereview@local>` 污染了 **81** 个被 Windows 重写的提交与 **58** 个 wave-1 提交;本地谱系经 parent/env rewrite 接到 GitHub `ff2994d9`,验证 **59** 个重写提交全部是 `Swung0x48 <swung0x48@outlook.com>`,tree/patch 等价。自此每阶段首个 commit 前必须先跑 `git var GIT_COMMITTER_IDENT`。这是过程修复,不计成 P5 实现产量。
|
||||||
|
|
||||||
|
## 30. P5 four-arm A/B on the Redmi(pending `ab-v1.md`)
|
||||||
|
|
||||||
|
本节只冻结协议,不填数字。设备是项目指定 Redmi;四臂用同一 native code 对照:
|
||||||
|
|
||||||
|
| arm | APK / env | 回答的问题 |
|
||||||
|
|---|---|---|
|
||||||
|
| pull | pull APK | 既有 pull 基线 |
|
||||||
|
| push | push APK | monolith push 边界 |
|
||||||
|
| split-inproc | split APK + `MOBILEGL_TRANSPORT=inproc` | 第二 apply 线程的 barrier / codec / copy 总成本 |
|
||||||
|
| split-no-env control | 同一 split APK,不设 transport env | Gradle flavour 本身是否改变 monolith;应与 push 对照 |
|
||||||
|
|
||||||
|
沿用设备协议:reboot-clean、同一风扇档与已验证定频、四臂交错配对;每个 trace 记录尾 200 帧 p50/p99、逐线程 CPU、`pmap/mpr/rsp`、进程 `VmHWM`,并保留 pin check 与 private log。A/B 后台运行、不阻塞 landing(ID-66);在 `~/w7/notes/p5/p5-results/ab-v1.md` 出现前,本节保持 **pending**,不从 desktop gate 或旧 APK 推算。
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# MGPipe:MobileGL 前后端拆分
|
# MGPipe:MobileGL 前后端拆分
|
||||||
|
|
||||||
> 状态:**P0、P0.5、P1、P2、P3a、P4a 已落地**(`feat/disaggregated@8c458cd5`,基线 `dev@9eae9858`)。第 43 天 GO/NO-GO 判定为**继续**。P4a(handle wave 2:Espryt 的 FBO / 纹理 / sampler / program 身份与描述符)已交付,Espryt 的对象类读点至此全部走句柄;**下一步 P3b/P4b**(深化:memo 重键、发射游标、raw-depth-fetch sampler 原生化)与 **P5**(传输 + inproc applier,也只依赖 P4a)。见 `ROADMAP.md`。
|
> 状态:**P0、P0.5、P1、P2、P3a、P4a、P5 已落地**(`feat/disaggregated@eec0e836`)。P5 已在完整门上跑出缩减路径首个 IPC 帧:`Clear` / `DrawArrays` / `ReadPixels` / `BlitFramebuffer` / `Present` 经同一套 wire codec 到同进程第二个 apply 线程,OpenRA 在 `inproc` 下两后端 2/2、SSIM 1.0。其余 64 个 class-C 槽仍具名 `Fatal{UnmigratedVerb}`;下一阶段先按 census 迁移它们,把真实负载完整搬上 apply 线程,再做 spawn。见 `ROADMAP.md`。
|
||||||
>
|
>
|
||||||
> 性能纪律(2026-09-08 起):逐线程 CPU 与 tracker 绝对 ns **对着 pull 臂基线记录**,不再作阻塞门(push 比 pull 多约 10% 逐线程 CPU 已被接受;该读数出自 -O0 APK,Release 基准线见 `MEASUREMENTS.md` §20),专门的优化阶段排在路线图推完之后。
|
> 性能纪律(2026-09-08 起):逐线程 CPU 与 tracker 绝对 ns **对着 pull 臂基线记录**,不再作阻塞门(push 比 pull 多约 10% 逐线程 CPU 已被接受;该读数出自 -O0 APK,Release 基准线见 `MEASUREMENTS.md` §20),专门的优化阶段排在路线图推完之后。
|
||||||
|
|
||||||
@@ -25,6 +25,27 @@ MGPipe 是 MobileGL 前端(`MG_State` + `MG_Impl`)与后端(`MG_Backend`
|
|||||||
|
|
||||||
三种构建/运行形态共用**同一份 backend 实现**:`monolith`(默认,接口在进程内直调)、`inproc`(同进程两个线程,CI 形态与渲染线程交付物)、`spawn`(`fork`+`execve` 出 server 进程,SPSC 共享内存 ring + FlatBuffers 控制面)。
|
三种构建/运行形态共用**同一份 backend 实现**:`monolith`(默认,接口在进程内直调)、`inproc`(同进程两个线程,CI 形态与渲染线程交付物)、`spawn`(`fork`+`execve` 出 server 进程,SPSC 共享内存 ring + FlatBuffers 控制面)。
|
||||||
|
|
||||||
|
## 运行 P5 split lane
|
||||||
|
|
||||||
|
本地门使用四个 flavour:`build-linux`(pull)、`build-push`(monolith push)、`build-verify`(影子比对)与 `build-split`(disaggregated + inproc)。split 运行时显式设置:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MOBILEGL_TRANSPORT=inproc ctest --test-dir build-split -L integration-split --output-on-failure
|
||||||
|
MOBILEGL_TRANSPORT=inproc ctest --test-dir build-split -L integration-gpu --output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
缩减路径的具名入口是 `DirectGLES.Split.*`;每条 entry 都带独立的 `MOBILEGL_LOG_FILE_PATH`,日志不共享,阴性控制也只读被选 entry 的私有文件。常用运行时旋钮:
|
||||||
|
|
||||||
|
| 变量 | 默认 | 用途 |
|
||||||
|
|---|---:|---|
|
||||||
|
| `MOBILEGL_IPC_VERB_BARRIER` | `1` | 每个 verb 等 `appliedSeq == emitSeq`;`0` 只作 E1 阴性控制 |
|
||||||
|
| `MOBILEGL_IPC_AUDIT` | `0` | apply 返回后以 `0xDD` 填退休 staging,查跨返回持针 |
|
||||||
|
| `MOBILEGL_IPC_STRICT_ERRORS` | `0` | 把 BARRIER-PULLED residual input 提升为具名 Fatal |
|
||||||
|
| `MOBILEGL_IPC_ADOPT_TIER` | `2` | P5 split 使用 emulated persistent-map 路径;接受 `auto/0/1/2` |
|
||||||
|
| `MOBILEGL_IPC_PERSISTENT_BLOCK_KB` | `64` | persistent-map 保守块推送粒度;`0` 是 E3(a) 阴性控制 |
|
||||||
|
|
||||||
|
Android 有三份 APK flavour:pull、push 与 split-inproc;构建映射分别由 Gradle properties `mobilegl.pipePush`、`mobilegl.buildDisaggregated`、`mobilegl.buildDisaggregatedInproc` 驱动。split APK 仍需运行环境 `MOBILEGL_TRANSPORT=inproc`;不设置时是 split build 的 monolith control arm。
|
||||||
|
|
||||||
## 文件地图
|
## 文件地图
|
||||||
|
|
||||||
| 文件 | 内容 |
|
| 文件 | 内容 |
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user