P5 — 传输 + inproc applier + 发射表(ff2994d9..37fc4fdb)
本页是该阶段的阶段汇总:阶段表行、实测与落地形状的完整文本(2026-09-24 从上层索引移入,原文照录)都在这里;上层只留摘要——
ROADMAP.md、MEASUREMENTS.md、ARCHITECTURE.md。文中file:line与"今天""当前"按各段写成时的头理解;文中的MEASUREMENTS.md §N/ARCHITECTURE.md §17.x编号保留,对照表见../README.md。
摘要
- 落地:同一 codec 上的
InProcessTransport;四种 build flavour(pull / push / verify / split);发射表三类 + caps mirror + reply mailbox;apply 线程终身持有 context;lockstep verb barrier;tight ReadPixels;persistent-map 块推送;G8 字段归属生成器;split 测试 / CI / APK 车道。八包 c0 / w1 / s1 / p1 / b1 / t1 / c1 / v1 + j0 / x2 / v1-r3 收尾。 - 门:joint OpenRA inproc 2/2 SSIM 1.0、
integration-split21/21、E1 14/14 红、G1 0/0/0/0。收尾头全门在 E3(a) 停止(设计性 skip 被判红),Part 2 / 4 未到达。 - 收官审查 1 blocker / 10 major / 2 minor → P5b 的 r1 / r2。Redmi 四臂 A/B 的 split 臂全部停在索引 draw,barrier tax 归 P5b。
- 流程在 P5 尾声改变(ID-66):不过度验证,每阶段收官一次异模型族审查。
阶段表行(原 ROADMAP.md)
- 阶段: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-split21/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
实测:P5(joint e61d0012 → 落地 eec0e836 → 收尾头 37fc4fdb)(原 MEASUREMENTS.md §6)
6.1 五部分门(joint)与落地快门
| 部分 | joint 实测 |
|---|---|
| 1 接口纯度 | include closure 4 probes / 0 problems;pull MG_Remote 符号 0、split 610;G1 .text 10806611 → 10806611、27814 符号 0/0/0/0;P3a/P4a G5 对 ff2994d9 byte-identical |
| 5 覆盖 / 生成器 | gen_pipe self-test 9/9;dirty-surface 27/27(UseProgram 一项明确 UNDECIDED);field ownership 15/15;emitter/CSO 185/185;verify controls 4/4 |
| 3 行为 A/B | G2 差 0;G14 0 / +42;unit 1816×3、split 2038;Wire 58/58;integration-gpu pull 1128、push 1128、split-monolith 1149;split-inproc 普查 426 pass / 185 skip / 511 abort / 27 fail;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{;OpenRA inproc 2/2 双后端 SSIM 1.0;push retrace 79/79;verify retrace 79/79 armed |
| 4 设备 | 未跑(joint 禁止 adb);见 §6.4 |
落地快门(eec0e836,ID-66):split unit 2038;integration-split 22/22;push integration-gpu 1128;G1 0/0/0/0 .text +0。
6.2 退出门 E1–E6 与 27 个 wrong-answer
| 门 | 实测与"为什么会红" |
|---|---|
| E1 barrier | reduced path 19 pass / 2 skip / 0 fail;MOBILEGL_IPC_VERB_BARRIER=0 选中的 14/14 全 abort,每个私有日志有自己的 Fatal{BarrierViolation, "<slot>"} |
| E2 OpenRA | 2/2 SSIM 1.0;x2:丢 29 clears 仍 SSIM 1.0(被后续地形 draw 覆盖),改为丢 758 DrawVbo 后 SSIM 0.000036;r2 验证真实 CTest 顺序 baseline → pull-library control → 恢复原库 → draw-drop,并断言库身份 |
| E3 persistent map | (a) 收尾头 6 selected 中 4 pixel red、2 条 TheMapLandsInTheArmItsLaneDeclares 设计性 skip 被 j0 判红 → r2 精选默认 / SmallRing 下 4 条 pixel case 各带自己的 assertion + 私有诊断;(b) ID-42 emulated membership green → 3 red → green;(e) x2 证明 wrap,r2 证明真实 retirement wait(1 MiB 臂 ringwraps=1 ringwaits=1,8 MiB 对照同时红) |
| E4 field ownership | 生成器 15/15;strict lane 19 abort / 2 skip,首条 Fatal{UnmigratedPipeInput, "GetTextureContextId@Clear"}——BARRIER-PULLED 债务的响亮读法 |
| E5 honest inproc | 19 pass / 2 skip;v1-r3 的 StagedShadowProductionTest 证明 ensure 上传 server shadow(删保护会读 client A 变红),覆盖 unmapped 对象;coherent-map 的 server 侧绕过由 r1 #1 关闭 |
| E6 phase gate | 普查在 v1-r3 修掉六条过宽 whole-store 拒绝后 432 / 185 / 505 UnmigratedVerb abort / 27 failed / 0 segfault(1149 项,~/w7/p5b-c0b-census-logs/results.json) |
| 27 个 wrong-answer 家族 | 条 | 去向 |
|---|---|---|
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 |
TextureParamsWithoutASamplerView |
1 | P6 inspection forwarder |
P4aFinalFixScenario FBO/RBO delete |
1 | 读回用 ReadPixels,完整像素因果未隔离;client-thread framebuffer death 归 r1 #2 |
上表是 P5 的历史去向。头上读数(
3c80cd62,P7 wave 3 同名重跑)见 §7.2 末:22 条 readback → 19 绿 + 3 条由错答变为具名停止(都是MOBILEGL_PIPE_PUSH=0的对照臂);3 条 query 全绿;inspection 与 FBO/RBO 各 1 条绿。
6.3 R-10、逐帧 ledger 与内存
规范 ledger(ProtocolSmokeTest 钉住):SEG_CMD 8 MiB / SEG_STAGE 32 MiB / SEG_REPLY 16 MiB / SEG_EVENT 256 KiB。MOBILEGL_PIPE_STATS_PERIOD=1 下 persistent-map 场景 pmap=600.00 B/帧, mpr=1, rsp=35(rsp 只是有 stamp 读点的下界)。inproc 进程峰值 RSS:server accept 时 11.5 MB、client teardown 141 MB(两角色共享一个进程,不是两个独立峰值)。
max record bytes(x2,37fc4fdb):Triangle / persistent map / OpenRA 25 帧 / SmallRing 都是 maxrec=784 B / SetVertexAttribDefaults,默认 cap 4 MiB(占 0.019%)——这些负载不需要 chunking;oversized DrawVbo 尾的 unit 具名拒绝 Fatal{RingOverrun, "DrawVbo"}。
内容分块落地(2026-09-20,1e7c372e buffer / 9469d48e texture):SEG_STAGE 仍是"一条记录一个整 blob"的 arena,但会超出它的内容由发射侧按 stage chunk 预算 MGPipeStageChunkBytes() = clamp(segment/4, 4096, segment)(默认 32 MiB → 8 MiB)切成多条 resource_subdata——buffer 范围走查与纹理一级的整宽 slab(服务端 StagedTextureStore::AdoptRun 拼回整级)。§7.2 普查为容纳单次 128 MiB 上传而显式设的 MOBILEGL_IPC_STAGE_MB=256 因此不再是这两条路径的必需;未接入分片的 record 类型仍由 Fatal{RingOverrun, "SEG_STAGE"} 具名拒绝。上段的 maxrec 数字是分块前的测量,当时分块后的逐 blob 字节分布尚无新测量;该分布与分块后的 maxrec 已在 §12.4 补测——结论是默认 8 MiB chunk 预算在已测的两条负载上从未被打到,maxrec 仍是 1808。
6.4 Redmi 四臂 A/B(split 未测)
会话 2026-09-16,runner eec0e836,三份 APK 源码头 joint e61d0012;臂 = pull APK / push APK / split APK + MOBILEGL_TRANSPORT=inproc / splitctl(split APK 不设 transport)。40 组前后 pin check 全 P/P,37.2–39.9 °C。27 组完成 / 13 组失败:全部 10 组 split 在 benchmark 前中止(improved-transparency 双后端 DrawElementsInstancedBaseVertex,其余 DrawElements),另 3 组是 rd12/DirectVulkan 的既有 scudo 崩溃。帧 p50 / p99(ms):
| case / backend | pull | push | splitctl |
|---|---|---|---|
| improved-transparency / DirectGLES | 10.535 / 25.415 | 12.106 / 26.973 | 12.235 / 27.131 |
| improved-transparency / DirectVulkan | 10.742 / 25.031 | 11.678 / 26.134 | 11.837 / 26.476 |
| fabric-sodium / DirectGLES | 8.314 / 9.573 | 8.311 / 9.701 | 8.303 / 9.486 |
| vanilla 1.21.4 / DirectVulkan | 1.043 / 2.293 | 1.159 / 2.404 | 1.179 / 2.426 |
| rd12 / DirectGLES | 7.999 / 22.089 | 11.105 / 24.865 | 11.261 / 24.771 |
splitctl 相对 push 的帧 p50 −0.1% – +1.6%(split build 的 monolith 臂与 push 同源等价)。barrier tax 在 P5 未测得,归 P5b(§7.4)。
6.5 收尾头停止点、r1 / r2
~/w7/p5-final-gate.log(37fc4fdb):构建 4 × rc 0;Part 1 G1 27,814 符号 0/0/0/0、.text +0、两条 G5 byte-identical;Part 5 完成;Part 3 unit 1817×3 / split 2086、Wire 58、pull/push GPU 1128、split-monolith 1149 零失败、reduced 22 零失败、broad lane 1149 selected(532 non-success,含 abort);E1 14 red;E3(a) 因 2 条设计性 skip 被 j0-v3 的逐选项拒绝判失败,Part 2 / 4 未到达。j0 的 skip 拒绝是对的(不能放宽),选择器才是错的。
收官审查(p5-close-codex-review.md,只读):1 blocker / 10 major / 2 minor(ID-73)。r1(核心四项):apply-role 不得进入 persistent-map producer;framebuffer death 转 apply mailbox;PACK_SWAP_BYTES 的 component / packed-word swap;command-ring retirement 等待与重试。r2(37fc4fdb..d50183cb,CI / 控制 / 跑器九项):broad debt lane 记录后继续硬门、全 skip 则 baseline 失败;E2 库身份 SHA256 恢复;E3(a) 精选 4 pixel case;ringwaits 只计真正阻塞的分配;split unit 强制 MOBILEGL_ITEST_REQUIRE_GPU=1;普查跑器零执行拒绝、launch 前清私有日志;G5 pin 自测驱动生产选择路径;c1f 改用 ID-67 用例。r2 包门:split unit 2087、reduced 22、push 1128 零失败;E1 14 own reds、E3(a) 4 own reds;smoke 16 core + 12 private;census 432/185/505/27。r2 没有新跑 pull G1(不影响 pull production code)。
过程记录(不计入实现产量):wave-1 跨族复审十项全部经独立 perturbation 确认(ring 空 wrap 算术、reply 几何差 16 B、blob 校验接受任意段、pad-bit 控制没发送该 bit、三个 CI 对照接受任意非零退出……);后续 v1 / c1 各轮的 review 计数在 ID-52/58/62/64;本地 rereview 身份污染的 81 + 58 个提交经 parent/env rewrite 接回 GitHub ff2994d9(ID-40),此后每阶段首个 commit 前先跑 git var GIT_COMMITTER_IDENT。这些数字是流程在 P5 尾声改变(ID-66)的原因。
落地形状(原 ARCHITECTURE.md §17.1–§17.4)
17.1 verb barrier 与诚实的同地址空间传输
P5 的 inproc 是真第二线程,但还是 lockstep:每条 class-B verb 发射后 client 的 EmitAndWait 等到 appliedSeq == emitSeq;MOBILEGL_IPC_VERB_BARRIER=1 默认开启。理由不是吞吐,而是 BARRIER-PULLED 字段(G8 表里目前 36 行)尚无记录载体;在这些字段退役前让两线程同时跑,server 会读到 client 的"未来值"(R-1)。barrier 是逐族可退役对象,不是 P6 transport 的要求;它的设备代价(barrier tax)见 MEASUREMENTS.md §7.4。
同一地址空间不得成为旁路(R-2):encoder 把 MGHostSpan::Ptr 恒写成 nullptr,内容 blob 必须带真实 SEG_STAGE offset / 非零 size;decoder 对四种形状分别 Fatal{ProtocolCorruption}。MapPersistent 在 split 恒 decline;MOBILEGL_IPC_AUDIT=1 在 retire 后把 staging 填 0xDD,让跨 applier 返回持针的实现下一次读取时可见地失败(R-11:任何 widened read 先过 RequireStagedCoverageForPendingRanges,否则 Fatal{StageSnapshotTooNarrow})。apply 角色不得进入 client 的 persistent-map producer(r1)。
reply mailbox 以记录序号作为 slot id(R-3):slot header 是 {Seq, Status, Size},acceptance 的 Bool 答案与 MapPersistent decline 都在既有 verb wait 内读取;Status=ERROR 一律 Fatal{ReplyError},未知 status 是 Fatal{ReplyStatusInvalid};读到 reply 之前先由 appliedSeq 证明该记录已离开 applier(R-5)。P9 才把这套同步 mailbox 推广成异步池。等待预算:普通 verb / 容量等待 120 s(Fatal{BarrierTimeout},ClientSession.cpp 的 kBarrierTimeoutMs);ClientWaitSync 的 applied/reply 预算 = ceil(timeout ns / 1e6) + 120 000 ms,有限 chunk 避开溢出。这条看门狗只判死锁(记录永不退役),不是性能门:lavapipe/llvmpipe 在 texture-handle 注册(vkCreateImageView → llvmpipe_register_texture)上可合法阻塞 apply 线程 29.3–39.7 s,故预算从原 30 s 提到 120 s——monolith 走同一路径本就没有这个上限。
17.2 71 槽的三类、caps 与 tight readback
client 表(Client/EmitTables.cpp)把后端函数表的 71 个槽分成三类,static_assert 钉住 A = 2(getter 从 caps mirror 本地回答)/ B = 54(发射:P5 的 Clear、DrawArrays、ReadPixels、Blit、Present + P5b 的 d1 19、i1 7、t2 6、f1 11、BlitNamedFramebuffer、sync 5)/ C = 15(Fatal{UnmigratedVerb} 具名拒绝,永不回落到 monolith applier——R-4)。applier 侧 33 条走生成路由表 + 4 条 escape,PipeCatalogueTest 钉 37;生成路由的完备性覆盖值调用与 &MGPipeApply* 地址取用(R-17)。
能力存活只读 CapsMirror 中的 MGPCaps::CallMask(R-8);server 的 consumer mask 由 backend 类型显式设置并以实际 op table 校验,永不从进程级 MGPipeGetResourceOps() 推导。成功的 MakeEGLCurrent / InitCapabilities 重新发布 snapshot,client 按 generation 采纳(R-12);相同 (dpy, draw, read, ctx) tuple 的重复 make-current 不重发(ID-67)。
ReadPixels 在线上恒为 tight:server 临时设 neutral pack,只向 reply 写 width*height*bytesPerPixel;client 用自己持有的 pack state scatter(含 PACK_SWAP_BYTES 的 component / packed-word swap,r1)。绑定 PACK PBO 时在 client 侧 Fatal{UnmigratedVerb, "ReadPixels+PACK_BUFFER"};reply 单槽 payload 上限 2 MiB - 16,更大 readback 的 carrier 留给 P6+(ID-47/57)。
17.3 server 角色、shadow 与退出
ServerLoop 的 mgl-srv-apply 是 native context 的终身 owner。ServerMakeEGLCurrent 对 tuple 只 bind 一次,client release 只记账、绝不让 apply thread native-unbind(ID-54)。罕见 EGL 操作经 caller-serialised one-slot control mailbox 进 apply thread;十二个 Server* forwarder 是唯一缝。有 backend 却无 thread 时 Fatal{ApplyThreadNotRunning},不允许回落到 app thread。framebuffer death 的驱动调用也经 mailbox 上 apply thread(r1)。
PipeApplier::ApplyOne 依次 stamp verb、decode/apply、清 stamp;只有 SessionConsumer::ApplyOne 每条记录把 appliedSeq 加一。StagedShadowStore 按 resource twin 复制并合并精确覆盖范围;Ops_H_SubData / flush / respecify 只把 server-owned copy 交给后端;有传输时 liveHostBase() 不得回落到 client 的 MappedData()(ID-50/52)。
退出顺序:ShutdownSplitRoles 先让 client publish 并 bounded-drain,再 shutdown transport / 唤醒 wait,随后 bounded-join apply thread;线程在仍持 context 时 detach decoder、销毁 private backend,最后才销毁 emitter 与 transport。
17.4 lane 隔离与阶段边界
每条 DirectGLES.Split.* entry 有独立 MOBILEGL_LOG_FILE_PATH;E1/E3 控制从被选 entry 的私有文件取 Fatal,且把"选中条目被跳过"判为失败(ID-53/62)。integration-split 是缩减路径的硬门;broad inproc integration-gpu 车道只记录普查、不设门(ID-65)。
里程碑记录(原 ROADMAP.md)
- P5 出口(2026-09-16):缩减路径首个 IPC 帧;最终全门在 E3(a) 停止;红米四臂的 split 均停在索引 draw,barrier tax 未测(归 P5b)。
本目录
| 文件 | 内容 |
|---|---|
BRIEF-P5.md |
BRIEF-P5 — 传输 + inproc applier + 发射表 |
PACKAGE-PREAMBLE.md |
P5 包通用前言 — 每个包开工前必读 |
scout-backend-install-and-thread.md |
P5 scout — backend installation, BackendObject_Remote, and the thread/EGL question |
scout-caps-reply-reverse.md |
P5 scout — the caps snapshot, the reply slot, and the reverse channel |
scout-gpu-writes-and-persistent-map-push.md |
P5 scout — GPU-written tracking and the persistent-map push |
scout-premortem.md |
P5 scout — adversarial pre-mortem |
scout-test-ci-plumbing.md |
P5 scout — test/CI plumbing a SPLIT arm needs |
scout-transport.md |
P5 scout — MG_Remote/Transport as it stands, and what P5 must add |
scout-unmigrated-census.md |
P5 scout — the unmigrated-input census |
scout-wire-codec.md |
P5 scout — the wire codec (G3) and the call catalogue's flags |
verb-census.md |
verb-census.md — which GlobalBackendFunctionsTable slots the reduced path actually reaches |
p5-results/ |
48 个文件:各包实现 / 评审 / joint / A/B 结果稿 |
prompts/ |
2 个文件:派包提示词 |