[docs] (P7): §12 - the one present per bsl-esc-menu replay is the trace's own two swaps and the harness's snapshot exit, so server reclaim must not assume a bounded frame

This commit is contained in:
2026-09-22 18:56:11 -04:00
parent 713bea9a8b
commit dbea871a06
+1 -1
View File
@@ -163,7 +163,7 @@ verify 今天只在 monolith 注册(`MG_IntegrationTest/CMakeLists.txt:1684-17
- 门 3 的「不确定」在 wave 1 E0 之前无法区分「同 case 多次结果不同」与「不同 case 各自低于阈值」;两个历史点值(0.988998 / 0.976494)无 per-case 归属。**已归属(W4,ID-P7-25)**:两个点值都是 OpenRA 同一帧里被静默丢掉的一段 draw(9836 / 14658 像素),run-ahead 与 spawn 臂都掷硬币;修复归 B3。
- ~~`TextureViewAliasScenario.TheOwnerUploadDrainRunsAgainAfterADrawBoundary` 在三条 split 臂按名排除~~ **已退(wave 2-D3,`6eaaf492`)**:split 的 clean gate 改读 storage record(`IsDrawSyncCleanByRecord` 走 `Desc.ViewOf` 到 owner,与 Magma 的 `ResolveWireTextureStorage` 同形),排除删除,三臂 3 红 → 14/14;P5E §5.2 改写。留下的:该场景的 Magma 臂只在 informational 层;`KHR-GL46.texture_view.coherency` 无 split 读数(门 5)。
- **OpenRA 调查裁判点名的 Magma 债(`notes/p7/device-window-1/W4-verify/README.md` §3b、`~/w7/notes/evidence/w4/judge.json`),B3 不动、记在这里**:`TryDrainFrameTransients` 的 wire-only 块 `CollectWireObjects(m_completedSubmitCounter, /*all=*/true)`(`VulkanRenderer.cpp:13526`)无视 `RetireWireObjects` 给未来对象打的 `submitIndex = m_submitCounter + 1` 标签(`WireDraw.inc:113-118, 175-194`);`HasPendingRecordedWork`(`:13435-13441`)看不见 pre-pass 命令流;`FlushWirePendingCommandsForTextureUpdate = !HasPendingRecordedWork() || FlushPendingCommands()`(`VulkanRenderer.h:148-152`)把「此刻没在录」当「没在飞」;`StagedTextureStore::AdoptRun` 在 extent 变化时不重置 `Bytes`/`Covered`(`StagedTextureStore.h:234-243` vs `:270-284`,一条单测即红);`FrameContext::WaitAndAcquireNextImage`(`FrameContext.cpp:303-312`)只凭槽 fence 释放中帧 flush 过的命令缓冲。本 trace 都不可达,但都是真债。
- **bsl-esc-menu-854 在 wire 臂上是内存缺陷不是排除项**(W4 §2/§3c):monolith 807 MiB 峰值通过;spawn 下 server 进程涨到 ~1.2 GiB 在 scudo 二级分配器 `internal map failure (Out of memory)` 死(系统尚余 8 GB → 是映射数或每进程上限,不是系统 OOM),client 同时 543 MiB;inproc 1.6 GiB 也死。**M1 已归因(主机 lavapipe,三臂同图)**:不是 store 的字节复制,是 split server **无界累积死 `VkBuffer`**——`RespecifyWireBuffer`(`VkBufferManager.cpp:189-224`)对每个 `glBufferData` 无条件 `DeferRelease` 进按帧槽分桶的 `m_deferredBufferReleases`,而桶只在 `BeginFrame`/`CollectAllDeferredReleases` 扫(`TryDrainFrameTransients` 与 present 路径),**pbuffer 回放整跑 server 只收到 1 条 present 记录**、drain 约每分钟成功两次 → 25 935 个活 VkBuffer(25 923 死)对 monolith 7 个,lavapipe 上每个一条 `memfd` 映射(27.4k → 41k),+12.2 MiB / 7.2 s,与真机 server 527 → 1162 MB 的爬升同量;轻例 `iris-bsl-in-world` 同形 1000×小(93 活 / 74 死)——随帧界之间的调用数增长,不是结构性。`StagedTextureStore` 是每层第二份拷贝(43 MiB)但平台;`PendingUploads` 0 字节(与 B3 无关);monolith 式条件 orphan 无效(6701 vs 6702)。附带:`CollectGarbage()`/`pruneWire`(`VulkanRenderer.cpp:6989`)在 `SetupDraw` 转 `SetupWireDraw` 之后、wire 臂从不执行。修复包 **M2**(`VkBufferManager.{h,cpp}`:按 serial 的 fence-gated 回收 + `MOBILEGL_IPC_WIRE_DEFERRED_MB` 水位线;red-once = 单帧内 N 次 respecify 后活 VkBuffer ≤ k×wire buffers)。**未答**:真机上是 `vm.max_map_count` 还是字节(采样器没记 maps 行数;Adreno 的 VMA 256 MiB 块推测是字节);pbuffer 回放为何只有一条 present(client 是否对 pbuffer 面跳过 present 记录——若是,server 侧所有帧界扫描都被饿死,另派包)。
- **bsl-esc-menu-854 在 wire 臂上是内存缺陷不是排除项**(W4 §2/§3c):monolith 807 MiB 峰值通过;spawn 下 server 进程涨到 ~1.2 GiB 在 scudo 二级分配器 `internal map failure (Out of memory)` 死(系统尚余 8 GB → 是映射数或每进程上限,不是系统 OOM),client 同时 543 MiB;inproc 1.6 GiB 也死。**M1 已归因(主机 lavapipe,三臂同图)**:不是 store 的字节复制,是 split server **无界累积死 `VkBuffer`**——`RespecifyWireBuffer`(`VkBufferManager.cpp:189-224`)对每个 `glBufferData` 无条件 `DeferRelease` 进按帧槽分桶的 `m_deferredBufferReleases`,而桶只在 `BeginFrame`/`CollectAllDeferredReleases` 扫(`TryDrainFrameTransients` 与 present 路径),**pbuffer 回放整跑 server 只收到 1 条 present 记录**、drain 约每分钟成功两次 → 25 935 个活 VkBuffer(25 923 死)对 monolith 7 个,lavapipe 上每个一条 `memfd` 映射(27.4k → 41k),+12.2 MiB / 7.2 s,与真机 server 527 → 1162 MB 的爬升同量;轻例 `iris-bsl-in-world` 同形 1000×小(93 活 / 74 死)——随帧界之间的调用数增长,不是结构性。`StagedTextureStore` 是每层第二份拷贝(43 MiB)但平台;`PendingUploads` 0 字节(与 B3 无关);monolith 式条件 orphan 无效(6701 vs 6702)。附带:`CollectGarbage()`/`pruneWire`(`VulkanRenderer.cpp:6989`)在 `SetupDraw` 转 `SetupWireDraw` 之后、wire 臂从不执行。修复包 **M2**(`VkBufferManager.{h,cpp}`:按 serial 的 fence-gated 回收 + `MOBILEGL_IPC_WIRE_DEFERRED_MB` 水位线;red-once = 单帧内 N 次 respecify 后活 VkBuffer ≤ k×wire buffers)。**未答**:真机上是 `vm.max_map_count` 还是字节(采样器没记 maps 行数;Adreno 的 VMA 256 MiB 块推测是字节)。**「只有一条 present」已答(P-present 调查)**:不是 pbuffer、不是 client 决定——该 fixture 1 303 535 次调用里只有 **2 次 `eglSwapBuffers`**(call 1 301 789 与目标 call 1 303 534),harness 在目标 swap 上先快照后 `exit`(apitrace `retrace_main.cpp` 的 `frameComplete` → `mobilegl_apitrace_exit` 抛出(`tools/trace_replay/CMakeLists.txt:186-189` 的宏替换),在 apitrace `glretrace_egl.cpp` 的 `frame_complete` 里、`drawable->swapBuffers()` 之前解栈),所以到达 MobileGL 的 swap = 1、present 记录 = 1、`OnPresent` = 1;规则 `presents = (swaps with call_no ≤ target) − 1`(OpenRA 30 → 29,B3 测得 33 次 `BeginFrame` = 29 present + 起会 + drain)。client 的 `SwapBuffers → BackendObject::SwapEGLBuffers → Present()` 链无任何 surface-kind 分支,credit 只停不丢。结论:**server 侧任何挂在 present 上的回收都不能假设一帧有界**(一帧可以是 1.3 M 调用的 Iris 换包重编译),M2 的按 serial 回收正是这个形状;`TryDrainFrameTransients` 的两道闸 + 每 8 次的节流不是替代品。附带债:`BackendObject.cpp:385-388` 单活动面守卫对多 surface 的 client 会静默丢 present(本 trace 不触发)——该给 `MGLOG_E_ONCE`/计数。
- `MEASUREMENTS.md` §7.2 的同名比对自 P5b 起未重跑;「22 → texture readback」「3 → query」两行债务的关闭以 wave 3 的重跑为准。
- Android 模拟器 retrace 车道每轮 2–6 例 flaky(含 monolith 对照):门 1 的任何模拟器证据都先过「连续 N 轮绿」再算数。
- **X1 之后的两条残余**(`notes/p7/x1-persistent-map-segv.md`):(a) 首次 push 后页面在映射存活期间重新武装,一个**屏蔽了 SIGSEGV 的非 GL 线程写者**仍会被杀——彻底关闭要把武装改成逐 buffer 可选,是设计改动;(b) `RefaultOfANonWriteAccess` 仍可能拒掉同 `(tid, pc, address)` 的一次合法重复写——延后武装后不再常见,未观察到,记录。