From 1de8f02ebe87ea60c07a063544207341c69bf729 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 22 Sep 2026 14:23:11 -0400 Subject: [PATCH] [MG_IntegrationTest, docs] (P7): the whole integration binary runs under Magma split, and it is one red Tier 2 replays the split-arm registrations - ~100 scenarios, the set Espryt's disaggregation work has carried since P5 - and it measured green on Magma across all three transports. That is a real result but it is NOT exit gate 1. The gate says the INTEGRATION BINARY is green under Magma split, and the set that names is the one the monolith DirectVulkan. arm runs: the whole suite minus MGL_ITEST_MONOLITH_MECHANISM_FILTER. 510 cases against tier 2's 102, and the readback matrices, the same-texture copy shapes and the odd-offset uniform ranges are in it and nowhere else in the disaggregated registry. integration-magma-full-{split,spawn,tcp}, in no gating step, private log per entry through a list of its own. THE RESULT: 453/0/57 on inproc, 453/0/57 on spawn, 454/1/57 on tcp - and not one of the 1530 entries reaches any of the tree's fifteen @P7 named refusals. The single red is IterationRPProgram203Scenario.FixedCompleteInputProducesFixedCompleteGoldenOutput on the TCP arm: one texel of 262656, texel 0, which is the case's own exposure value (IterationRPProgram203Scenario.cpp:371, actual half bits (0x357a, 0x4b65) against golden (0x3a74, 0x4821)). Deterministic 5/5 on tcp; 5/5 GREEN on inproc, on spawn and on the monolith control. spawn and tcp differ only in MOBILEGL_IPC_DATA, so the suspicion is the STREAM data path and not "two processes"; the GLES tcp lane is green in the same run, so it is not the fixture. Not fixed here - it is what the census is for. TWO ENVIRONMENT DIFFERENCES FROM THE GATED TIERS, both measured rather than assumed: * NO MGITEST_SPLIT_LANE=1. That marker arms ScenarioFixture's destructor assertion - a case in an armed split lane must have moved the client encoder's record ordinal - which is right for a curated lane and wrong for a whole-binary census. With it set, the first run produced 13 reds, all `EmitSeq was 20 at SetUp and is 20 now`: AdvertisedLimitsScenario (8), SpirvShaderBinaryScenario (4) and ProgramPipelineScenario.AReservedName - a limits query is answered from the client's CapsMirror and a shader-binary error surface never reaches a verb. Those 13 would red on a DirectGLES census too. What it gives up is stated in the comment: this tier does not prove its records crossed, and the tcp topology proof is inert in it. * DualBlockScenario.* filtered out. Its green REQUIRES MOBILEGL_IPC_ROLE_SPLIT_STATE=1 and a census must not set that knob; without it the case is red by name, which is its documented negative-control behaviour. The monolith arm skips it for the same class of reason. CtWireScenario gets MOBILEGL_TEST_SERVER_COUNTERS=1 in this tier - a switch that makes a counter readable, not an oracle that asserts - because without it the spawn arm's ApplierReset case reds on "server control-record telemetry missing", which says nothing about Magma. The strict-arming, pmap and persistent-map-arm markers stay out. The inproc-only exclusion in spawn_lane_parity.py is now PER TIER: in the gated tier the two scenarios are registered on the inproc arm alone, in the census they are on every arm and simply skip, so excluding them there would manufacture a spurious "extra". Measured after the change: every pre-existing lane unchanged and green (magma-split 73, spawn 52, tcp 54, all-* 102/102/104, GLES 186/102/104, buffers 19, runahead 14, caches 7), the dual-block census 257 green / 2 skipped / 0 red with an empty ratchet, both new CI steps green, parity RC=0 across all three tiers, G14 4155 -> 6095 with removed=0. The note now carries the grouped red list, the 57 named skips by reason, the four pieces of evidence that the tcp red is a defect and not plumbing, and six findings - the first being that wave 2's clusters cannot be scheduled from this lane's red list, because on lavapipe there is essentially none. --- MobileGL/MG_IntegrationTest/CMakeLists.txt | 83 ++++ .../Harness/SplitLogPaths.cmake.in | 23 ++ .../notes/p7/magma-two-process-first-run.md | 383 ++++++++++-------- scripts/ci/spawn_lane_parity.py | 23 +- 4 files changed, 348 insertions(+), 164 deletions(-) diff --git a/MobileGL/MG_IntegrationTest/CMakeLists.txt b/MobileGL/MG_IntegrationTest/CMakeLists.txt index 39b00aea..59f2667b 100644 --- a/MobileGL/MG_IntegrationTest/CMakeLists.txt +++ b/MobileGL/MG_IntegrationTest/CMakeLists.txt @@ -3090,6 +3090,89 @@ if (MOBILEGL_BUILD_DISAGGREGATED) endforeach() endif() +# ===================================================================================== +# P7 PACKAGE L: THE WHOLE INTEGRATION BINARY UNDER MAGMA SPLIT - TIER 3, INFORMATIONAL +# ===================================================================================== +# +# WHY A THIRD TIER, AND WHY IT IS THE ONE THAT ANSWERS THE EXIT GATE. Tier 2 above replays the +# split-arm registrations, which is ~100 scenarios - the set Espryt's disaggregation work has +# been carrying since P5. It measured GREEN on Magma, all three transports, and that is a real +# result but it is NOT exit gate 1. The gate says the INTEGRATION BINARY is green under Magma +# split, and the set that phrase names is the one the monolith `DirectVulkan.` arm runs: the +# whole suite minus MGL_ITEST_MONOLITH_MECHANISM_FILTER (the mechanism oracles, which toggle +# process-local push masks, pointer-key ABA, direct persistent adoption or synchronous stats +# slots and therefore must not inherit a transport). 511 cases, against tier 2's 102. +# +# THIS IS WHERE THE @P7 REFUSALS LIVE. None of tier 2's scenarios reaches one; the readback +# matrices, the same-texture copy shapes and the odd-offset uniform ranges do, and they are in +# this set and nowhere else in the disaggregated registry. THE FIRST RUN'S RED LIST IS WHAT +# WAVE 2's CLUSTERS ARE SCHEDULED FROM - see notes/p7/magma-two-process-first-run.md. +# +# IN NO CI GATING STEP, and that is the whole design: a lane that must be green cannot carry a +# census. A case leaves this tier for a gated one with the commit that retires its blocker. +# The label spelling follows tier 2's rule (`ctest -L` is a regex, ID-131): the tier word goes +# in the MIDDLE, so `-L integration-magma-split` and `-L integration-magma-all-split` cannot +# reach `integration-magma-full-split` and vice versa. +# +# THE SAME PRIVATE-LOG DISCIPLINE as every other split-family entry, through a list of its own +# rather than the shared MGL_SPLIT_ARM_TEST_LISTS: that list ALSO carries the per-entry lane +# markers (strict-arming, pmap, server counters) and applying them to a census would arm three +# unrelated oracles on cases that are here to be read, not to assert. SplitLogPaths.cmake.in +# walks this list for the log path alone. +# +# PLACED AFTER TIER 2 AND BEFORE THE configure_file, for that file's stated reason. +# +# TWO DIFFERENCES FROM TIERS 1 AND 2's ENVIRONMENT, BOTH MEASURED RATHER THAN ASSUMED. +# +# 1. NO MGITEST_SPLIT_LANE=1. That marker arms ScenarioFixture's destructor assertion +# (ScenarioFixture.h:85-100): a case in an armed split lane must have MOVED the client +# encoder's record ordinal, because "the workload drew, cleared and read pixels, so +# records were due". That is exactly right for a CURATED lane, where every entry draws. +# It is wrong for a whole-binary census, which also contains query-only cases: the first +# run of this tier with the marker set produced 13 reds - AdvertisedLimitsScenario (8), +# SpirvShaderBinaryScenario (4) and ProgramPipelineScenario.AReservedName… - every one of +# them `EmitSeq was 20 at SetUp and is 20 now`, because a limits query is answered from +# the client's CapsMirror and a shader-binary error surface never reaches a verb. Those +# 13 would red on a DirectGLES census too; they are a property of the census, not of +# Magma, and leaving them in would have buried the real list under noise. +# WHAT THIS GIVES UP, stated rather than discovered later: this tier does not prove its +# records crossed the wire, and the tcp arm's "Dial=Connect created no local server child" +# topology proof (ScenarioFixture.h:160-171, inside the same armed block) is inert here. +# Tiers 1 and 2 keep both, and they are the tiers that gate. MGITEST_TCP_LANE is still in +# the shared tcp fragment - it simply has no reader in this tier. +# 2. DualBlockScenario.* IS FILTERED OUT. Its green REQUIRES MOBILEGL_IPC_ROLE_SPLIT_STATE=1, +# and a census must not set that knob - under it every barrier-pulled read aborts, which +# would replace this tier's subject with a different experiment. Without the knob the case +# is RED BY NAME (`MGPipeRoleSplitRehearsalActive() is false`), which is its documented +# negative-control behaviour and not a finding. The monolith `DirectVulkan.` arm has the +# same case and it SKIPS there, because that runtime is not split at all. Its own lane, +# `integration-dualblock-split`, is where it is read. +if (MOBILEGL_BUILD_DISAGGREGATED) + set(MGL_MAGMA_FULL_TEST_LISTS "") + foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS) + mgl_itest_magma_arm_shape(${mglItestArm}) + string(TOUPPER "${mglItestArm}" mglItestArmUpper) + mgl_itest_join_environment(mglItestMagmaFullEnvironment + "MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ITEST_REQUIRE_GPU=1" + ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV} ${mglItestArmTransportEnv}) + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectVulkan.${mglItestArm}.Full." + TEST_LIST "MGL_MAGMA_FULL_TESTS_${mglItestArmUpper}" + TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:DualBlockScenario.*" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-magma-full-${mglItestArmLower}" + TIMEOUT ${MGL_ITEST_TIMEOUT} + ${mglItestArmProperties} + ENVIRONMENT "${mglItestMagmaFullEnvironment}" + ) + list(APPEND MGL_MAGMA_FULL_TEST_LISTS "MGL_MAGMA_FULL_TESTS_${mglItestArmUpper}") + endforeach() + message(STATUS "Integration tests: P7 package L tier 3 - the whole integration binary on " + "DirectVulkan x {inproc, spawn, tcp} under the informational " + "integration-magma-full-{split,spawn,tcp} labels (no CI gate)") +endif() + if (MOBILEGL_BUILD_DISAGGREGATED) # LAST, so every mgl_itest_register_split_arms call above has already contributed its list # name. Apply per-entry paths after GoogleTest discovery has populated the TEST_LISTs. diff --git a/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in b/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in index a95fe114..722fbb20 100644 --- a/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in +++ b/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in @@ -29,6 +29,29 @@ foreach(listName IN ITEMS @MGL_SPLIT_ARM_TEST_LISTS@) endif() endforeach() endforeach() +# P7 package L tier 3: the whole-suite Magma census. A LIST OF ITS OWN, and the log path is the +# ONLY property it gets - the loop above also arms the strict-arming, pmap and server-counter +# lane markers by entry name, and a census is here to be READ, not to assert three unrelated +# oracles it never opted into. The path itself is not optional: these entries are +# DirectVulkan.{Split,Spawn,Tcp}. names, so split_log_paths.py's ownership gate requires exactly +# one absolute private path each, and on the spawn and tcp arms two processes append to it. +# +# ONE EXCEPTION, AND IT IS TELEMETRY RATHER THAN AN ORACLE: CtWireScenario reads the server's +# own control-record tallies, and without MOBILEGL_TEST_SERVER_COUNTERS=1 they are not published +# at all - the case then reds on `server control-record telemetry missing`, which says nothing +# about Magma. Measured: that is exactly what the spawn arm's ApplierReset case did on this +# tier's first run. A switch that makes a counter readable is not the same kind of thing as the +# strict-arming, pmap or persistent-map-arm markers above, which make a case ASSERT something it +# never opted into, and those stay out of the census. +foreach(listName IN ITEMS @MGL_MAGMA_FULL_TEST_LISTS@) + foreach(entry IN LISTS ${listName}) + set_tests_properties("${entry}" PROPERTIES ENVIRONMENT + "MOBILEGL_LOG_FILE_PATH=@CMAKE_CURRENT_BINARY_DIR@/split-logs/${entry}.log") + if(entry MATCHES "CtWireScenario\\.") + set_tests_properties("${entry}" PROPERTIES ENVIRONMENT "MOBILEGL_TEST_SERVER_COUNTERS=1") + endif() + endforeach() +endforeach() foreach(entry IN LISTS MGL_SPLIT_PA_STRICT_DRAW_TESTS MGL_SPLIT_PA_STRICT_DISPATCH_TESTS) set_tests_properties("${entry}" PROPERTIES ENVIRONMENT "MOBILEGL_LOG_FILE_PATH=@CMAKE_CURRENT_BINARY_DIR@/split-logs/${entry}.log") diff --git a/docs/Disaggregated/notes/p7/magma-two-process-first-run.md b/docs/Disaggregated/notes/p7/magma-two-process-first-run.md index 907fc716..0e13fbcd 100644 --- a/docs/Disaggregated/notes/p7/magma-two-process-first-run.md +++ b/docs/Disaggregated/notes/p7/magma-two-process-first-run.md @@ -5,63 +5,94 @@ > (`/usr/share/vulkan/icd.d/lvp_icd.json`,系统唯一 ICD),`build-split` = Release / clang / ccache / > `DISAGGREGATED=ON` `INPROC=ON` `PIPE_PUSH=ON` `BUILD_INTEGRATION_TEST=ON`, > `MOBILEGL_ITEST_TCP_ENDPOINT=tcp://127.0.0.1:40713`(本树专用端口,避免与兄弟树的 40613 撞车)。 +> +> 本文记两轮:**第一轮**(提交 `e22561aa..a6d805cc`)铺了 tier 1 / tier 2;**第二轮**(集成者追加指令, +> 提交 `f28409be..`)按「出口门 1 = 整个集成二进制」的读法加了 **tier 3 全量普查**,并裁定了 ICD 与 +> retrace 旋钮两处不对称。 ## 0. 一句话结论 -**仪器已经存在,而首轮不是红的。** `mgl_itest_register_split_arms` 现在带后端维度,Magma 的六条手铺车道 -各自长出 spawn / tcp 两条臂,另有一档信息性车道把 DirectGLES split 臂跑的**每一个**场景都在 DirectVulkan × -{inproc, spawn, tcp} 上跑一遍。在 lavapipe 主机上,**这 410 条新条目 0 红**。 +**仪器已经存在;把整个集成二进制铺到 Magma × 三条传输之后,红名单是 1 条。** -因此本包交付的不是「红名单 = P7 工作清单」,而是三件比它更硬的事实: +三档车道、1940 个新条目、每一条都实跑过: -1. **出口门 1 的主机半边今天就是绿的**:Magma × 两进程,73 + 52 + 52 + 102 × 3 条目,零失败。计划 §1.3 - 假设的红名单在主机口径下是**空集**;P7 剩下的 `@P7` 拒绝退役必须靠**真机**(wave 1)、**retrace 矩阵** - 与**更宽的场景普查**(P3b/P4b wave 2-D)去触发,而不是靠这条集成车道。这条判断本身就值一次裁定。 -2. **两条 Magma 车道在结构上就跑不了两进程**,首轮如实红了 21 条并已按仪器纪律收回单臂(§3)。 -3. **死亡通知的前提条件修好之后,Magma spawn 的 `object_death` 当场就通了**(§5)——比计划预期的 - 「Magma 仍然 0」更进一步,且把剩余缺口精确定位到 **inproc 臂**。 +- **tier 1 门控**(六条手铺 Magma 车道 × 三臂):73 / 52 / 52,**0 红**。 +- **tier 2 信息档**(split 臂跑的 ~100 个场景 × 三臂):102 × 3,**0 红**。 +- **tier 3 全量普查**(**整个集成二进制**,即 monolith `DirectVulkan.` 臂用的同一过滤器,× 三臂): + 510 × 3,**split 0 红 / spawn 0 红 / tcp 1 红**。 + +那唯一的一条红是真东西,不是管道: +`IterationRPProgram203Scenario.FixedCompleteInputProducesFixedCompleteGoldenOutput` 在 **tcp(stream +数据面)上确定性地**(5/5)少算对了一个 texel——**只差第 0 号 texel,就是曝光值**——而 inproc、spawn(shm +数据面)与 monolith 各 5/5 全绿。详见 §5。 + +因此对计划 §1.3 的修正结论是:**主机 × lavapipe 口径下,P7 出口门 1 的集成半边只欠一条**,而且欠的不是 +`@P7` 具名拒绝——**树上 15 处 `@P7` 拒绝没有一处被这 1530 条全量条目触发**。wave 2 的 A/B/C 三簇如果指望 +从这条车道拿红名单,拿不到;它们的红名单必须来自 **wave 1 真机**、**retrace 全矩阵**和 **P3b/P4b 的场景 +普查**。这条车道的职责应改为**回归门 + stream 数据面的显微镜**。 ## 1. 交付物与文件 | 交付 | 文件 | 要点 | |---|---|---| | 后端维度 | `MobileGL/MG_IntegrationTest/CMakeLists.txt` | `mgl_itest_register_split_arms_for_backend( [stems])` + 同名薄包装保持 32 个调用点不变;`MGL_ITEST_VULKAN_{SPLIT,SPAWN,TCP}_ENVIRONMENT`;`mgl_itest_magma_arm_shape()` 供六条手铺车道复用同一套臂形状 | -| 两档标签 | 同上 | 见 §2。CMake 注释里写死了两档的定义、升档规则与标签拼写的正则理由 | +| 三档标签 | 同上 | 见 §2。CMake 注释里写死了三档的定义、升档规则与标签拼写的正则理由 | +| ICD 裁定 | 同上 | 六条 Magma 车道从 `${MGL_ITEST_COMMON_ENV}` 改为 `${MGL_ITEST_VULKAN_ENV}`;NamedBlit / P5fRsp 两块按**后端**选,GLES 半边不拿 VK 钉 | | 死亡通知前提 | `MobileGL/MG_Remote/Client/WireTables.cpp` | 去掉 `ActiveBackendType == DirectGLES`,保留 `Transport == Spawn` 与 `GetStateObjectDeathOps() == nullptr` 两条(P6.5 原意的两半) | -| 私有日志纪律 | `MobileGL/MG_IntegrationTest/Harness/split_log_paths.py` | `is_split` 前缀补 `DirectVulkan.Spawn.` / `DirectVulkan.Tcp.` | -| 名集合门 | `scripts/ci/spawn_lane_parity.py` | 新增 Magma 两档的三臂比对 + 两条具名豁免 | -| CI | `.github/workflows/test.yml` | retrace-split 补三个 iterationrp 旋钮;新增 magma-spawn/-tcp 门控步骤与 buffers 子标签的 `require_green` | +| 私有日志纪律 | `Harness/split_log_paths.py`、`Harness/SplitLogPaths.cmake.in` | `is_split` 前缀补 `DirectVulkan.Spawn.` / `DirectVulkan.Tcp.`;tier 3 走**自己的**列表,只发日志路径 + CtWire 的计数器开关 | +| 名集合门 | `scripts/ci/spawn_lane_parity.py` | 新增三档的三臂比对(逐档的 inproc-only 豁免) | +| CI | `.github/workflows/test.yml` | retrace-split 补**五个** Magma 旋钮;新增 magma-spawn/-tcp 门控步骤与 buffers 子标签的 `require_green` | -## 2. 两档车道(这是本包的主结构) +## 2. 三档车道(本包的主结构) **第一档,门控。** `integration-magma-split`(inproc,**含义不变**:同样 73 条、同样的名字、同样的标签、 -同样的私有日志路径)+本包新增的 `integration-magma-spawn` / `integration-magma-tcp`。跑的是六条**手铺** -Magma 车道(Fm / Buffers / RunAhead / Caches / NamedBlit / P5fRsp),因为每条都带自己的 flavour(strict + -dual-block、adopt tier、run-ahead credit、cache pin),共享的场景过滤器表达不了。**一条标签只有在实测绿之后 -才准进门控步骤**——本包两条都实测绿,所以进了(§6)。 +同样的私有日志路径)+ `integration-magma-spawn` / `integration-magma-tcp`。跑的是六条**手铺** Magma 车道 +(Fm / Buffers / RunAhead / Caches / NamedBlit / P5fRsp),因为每条都带自己的 flavour(strict + dual-block、 +adopt tier、run-ahead credit、cache pin),共享的场景过滤器表达不了。**一条标签只有在实测绿之后才准进门控 +步骤**——两条都实测绿,所以进了(§7)。 **第二档,信息性。** `integration-magma-all-{split,spawn,tcp}`:DirectGLES split 臂跑的每一个场景,在 -DirectVulkan 上,三条传输各一遍。**不在任何 CI 门控步骤里**,它的职责就是**能红而 CI 仍绿**。它由宏记录的 -调用列表**回放**生成(`MGL_SPLIT_ARM_CALLS`,32 次调用),所以明天给 split 臂加一个场景,Magma 普查当天 -跟着长——这是 P6 `t6` 给 spawn 臂赢下的同一条论证,往后端方向再走一维。 +DirectVulkan 上,三条传输各一遍。由宏记录的调用列表**回放**生成(`MGL_SPLIT_ARM_CALLS`,32 次调用),所以 +明天给 split 臂加一个场景,Magma 普查当天跟着长。 -三条臂里**包含 inproc**,这是它的诊断半边:spawn/tcp 红而 inproc 绿 = 两进程缺陷;三条都红 = Magma 自己缺 -动词,归 wave 2 某个簇。没有 inproc 臂的话每一条红都要手工复跑一次才能分类。 +**第三档,全量普查(集成者追加)。** `integration-magma-full-{split,spawn,tcp}`:**整个集成二进制**,即 +monolith `DirectVulkan.` 臂用的同一过滤器(`-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}`, +`CMakeLists.txt:770-778` 的形状),510 个用例 × 三臂。**出口门 1 说的是这个集合**,不是 tier 2 的 102 个。 +tier 2 里没有一个场景能走到 `@P7` 拒绝;回读矩阵、同纹理 copy 形状、奇偶数偏移的 uniform range 这些能走到的, +只在这一档里。 -**标签拼写是按 `ctest -L` 的正则选的**(ID-131 的规矩,本文件已经为它付过两次学费): -`-L integration-magma-spawn` **不得**选中第二档,所以档位词放**中间**——`integration-magma-all-spawn` 不含 -`integration-magma-spawn` 子串,而显然的 `integration-magma-spawn-all` 含,会把 ~100 条预期可红的条目悄悄 -拖进门控车道。六种拼写双向都查过。子标签同理:inproc 臂保留历史名 `integration-magma-buffers`(CI 那一步 -按名字 require_green 它的 19 条),其余臂把臂词放**前面**(`integration-magma-spawn-buffers`),两个选择 -互相够不着。 +三档**都包含 inproc 臂**,这是诊断半边:spawn/tcp 红而 inproc 绿 = 两进程缺陷;三条都红 = Magma 自己缺动词。 +§5 的那条红正是靠这个判出来的。 -## 3. 首轮结果(逐车道) +**标签拼写是按 `ctest -L` 的正则选的**(ID-131 的规矩):档位词放**中间**——`integration-magma-all-spawn` / +`integration-magma-full-spawn` 都不含 `integration-magma-spawn` 子串,而显然的 `…-spawn-all` 含,会把上千条 +预期可红的条目悄悄拖进门控车道。九种拼写双向都查过。子标签同理:inproc 臂保留历史名 +`integration-magma-buffers`(CI 那一步按名字 require_green 它的 19 条),其余臂把臂词放**前面**。 -统计口径:`ctest --output-junit` 的 testcase,PASS / FAIL / SKIP 按 JUnit 判定;tcp 车道的条目数含 -`TcpServer.Start` / `TcpServer.Stop` 两条 fixture(每条 tcp 条目都 `FIXTURES_REQUIRED mobilegl-tcp`, -ctest 会把它们一起列进标签)。门控三档按 CI 的 job 环境跑(`MOBILEGL_ITEST_REQUIRE_GPU=1` -`MOBILEGL_IPC_STRICT_ERRORS=1` `MOBILEGL_IPC_ROLE_SPLIT_STATE=1`,`-j 2`);信息档与 GLES 档按普通口径 -(`REQUIRE_GPU=1`,`-j 8` / `-j 4`)。 +### 2.1 tier 3 的环境与 tier 1/2 差两处,两处都是实测出来的 + +1. **不设 `MGITEST_SPLIT_LANE=1`。** 该标记武装 `ScenarioFixture` 析构里的断言 + (`Harness/ScenarioFixture.h:85-100`):**在武装的 split 车道里跑过的用例必须让客户端编码器的记录序号 + 前进**,理由是「workload drew, cleared and read pixels, so records were due」。对一条**策展过的**车道这 + 完全正确;对**整个二进制**的普查它是错的——普查里还有纯查询用例。**第一次带着这个标记跑,13 条红**: + `AdvertisedLimitsScenario`(8)、`SpirvShaderBinaryScenario`(4)、 + `ProgramPipelineScenario.AReservedNameTakesStateBeforeItIsAProgramPipeline`(1),每一条都是 + `EmitSeq was 20 at SetUp and is 20 now`——limits 查询由客户端 CapsMirror 就地回答,shader-binary 的错误 + 面根本到不了动词。**这 13 条在 DirectGLES 的全量普查上也会红**:它是普查的属性,不是 Magma 的属性。 + **放弃了什么(明写)**:这一档不证明自己的记录过了线,tcp 臂的「Dial=Connect 没有拉起本地 server 子进程」 + 拓扑证明(`ScenarioFixture.h:160-171`,在同一个武装块里)在这里是哑的。tier 1/2 两样都保留,而它们才是 + 门控的那两档。 +2. **`DualBlockScenario.*` 被过滤掉。** 它的绿**要求** `MOBILEGL_IPC_ROLE_SPLIT_STATE=1`,而普查绝不能开这个 + 旋钮——开了之后每一次 barrier-pulled 读都 abort,普查的主题就换成了另一个实验。不开则它**按名字红** + (`MGPipeRoleSplitRehearsalActive() is false`),这是它**写在案的负控行为**,不是发现。monolith + `DirectVulkan.` 臂里同一条用例是 **SKIP**(那个运行时根本不是 split)。它自己的车道 + `integration-dualblock-split` 才是读它的地方。 + +## 3. 车道结果(逐档、逐臂) + +统计口径:`ctest --output-junit` 的 testcase;tcp 车道的条目数含 `TcpServer.Start` / `TcpServer.Stop` 两条 +fixture。门控三档按 CI 的 job 环境跑(`MOBILEGL_ITEST_REQUIRE_GPU=1` `MOBILEGL_IPC_STRICT_ERRORS=1` +`MOBILEGL_IPC_ROLE_SPLIT_STATE=1`,`-j 2`);信息档与全量档按普通口径(`REQUIRE_GPU=1`,`-j 8`)。 | 车道 | 条目 | PASS | FAIL | SKIP | 与基线比 | |---|---|---|---|---|---| @@ -71,21 +102,16 @@ ctest 会把它们一起列进标签)。门控三档按 CI 的 job 环境跑 | `integration-magma-all-split` | 102 | 100 | **0** | 2 | 新增(信息性) | | `integration-magma-all-spawn` | 102 | 100 | **0** | 2 | 新增(信息性) | | `integration-magma-all-tcp` | 104(102 + 2 fixture) | 102 | **0** | 2 | 新增(信息性) | -| `integration-split`(GLES) | 186 | 186 | 0 | 0 | 186 / 102 comparable,与基线相同 | +| **`integration-magma-full-split`** | **510** | **453** | **0** | **57** | 新增(全量普查) | +| **`integration-magma-full-spawn`** | **510** | **453** | **0** | **57** | 新增(全量普查) | +| **`integration-magma-full-tcp`** | **512**(510 + 2 fixture) | **454** | **1** | **57** | 新增(全量普查) | +| `integration-split`(GLES) | 186 | 186 | 0 | 0 | 与基线相同 | | `integration-spawn`(GLES) | 102 | 102 | 0 | 0 | 与基线相同 | | `integration-tcp`(GLES) | 104 | 104 | 0 | 0 | 与基线相同 | +| `integration-magma-{buffers,runahead,caches}` | 19 / 14 / 7 | 全绿 | 0 | 0 | 与基线相同 | -**六条 Magma 车道的 SKIP 全部是具名的、两种**: - -- 门控三档的 2 条是 `ClipDistanceScenario.{ADisabledClipDistanceRemovesNothing, - TheEnablesAreIndependentPerDistance}`,理由「lavapipe clips by a DISABLED gl_ClipDistance …」——inproc - 臂上 `split_log_paths.py` 的 `DUALBLOCK_ALLOWED_SKIPS` 已经收录了同两条的 Split 拼写(`:156-157`)。 -- 信息档的 2 条是 `CtWireScenario.{Texture,Framebuffer}DeathCrossesAndTheRecycledSlotAnswersTheNewObject`, - 理由 `object_death is produced by the DirectGLES death-notice ops; DirectVulkan has none until P7` - (`Scenarios/CtWireScenario.cpp:152-155` / `:208-211`)。**这两条就是 wave 2 包 C 的债,见 §5。** - -**arming 证据**(不是「跑了没红」,是「确实跑了两个进程、确实是 Magma」):483 条 DirectVulkan split 家族 -条目**每条恰好一个**私有绝对日志路径(`SplitLogPaths.PrivateAndDistinct` 绿),落盘 306 对 +**arming 证据**(不是「跑了没红」,是「确实跑了两个进程、确实是 Magma」):DirectVulkan split 家族条目 +**每条恰好一个**私有绝对日志路径(`SplitLogPaths.PrivateAndDistinct` 绿),落盘成对的 `.client.log` / `.server.log`;任取一对读到 ``` @@ -93,49 +119,75 @@ client: Config: Active backend type set to DirectVulkan client: Config: MOBILEGL_TRANSPORT=spawn - the MGPipe record stream crosses a real ring to an apply thread in ANOTHER PROCESS client: MG_Remote client: spawn ARMED - the server role runs in pid 130832, reached at "@mgl-130770-106887814518704" server: MG_Remote server: pid=130832 transport=spawn role=server ready control=unix data=shm -server: Config: Active backend type set to DirectVulkan +server: MG_Remote server: pid=625725 transport=spawn role=server ready control=tcp data=stream (tcp 臂) ``` -## 4. 红名单:首轮唯一的两组,都是**车道管道**,都已按仪器纪律处置 +## 4. 全量普查的 57 条 SKIP:全部具名,没有一条是「静默的」 -第一次把三条臂加给全部六条 Magma 车道时,spawn 与 tcp 各红 **21** 条,两臂**逐条相同**。按「Fatal 家族 + -消息 + 哪个角色日志」分组的首阻塞如下——**两组都不是 server 以 `@P7` 名字中止,不是错误像素,不是超时挂起**, -而是**场景本身只能在进程内跑**: +三条臂的 57 条 SKIP 逐条相同,按理由归组(`integration-magma-full-split` 口径): -| 组 | 条数 | 首阻塞 | 角色日志 | 归类 | -|---|---|---|---|---| -| **P1 run-ahead hold** | 14(`MagmaRunAheadScenario.*` × credit 1/3) | `MagmaRunAheadScenario.cpp:134: Value of: WaitForSplitApplyHoldForTesting() Actual: false Expected: true` + `the clear waited for apply instead of returning while its server batch was held`,随后 `:170` `HoldNextBatch() ... generates new fatal failures`。**两个角色日志里都没有任何 `Fatal{` / `Refuse{`** | `magma-runahead-{spawn,tcp}-credit{1,3}-*.{client,server}.log` | 车道管道 | -| **P2 cache peek** | 7(`MagmaWireCacheScenario.*`) | `MagmaWireCacheScenario.cpp:53: Expected equality of these values: runtime.transportName Which is: "non-monolith" / "inproc"`。同样**零 Fatal** | `magma-caches-{spawn,tcp}-*.{client,server}.log` | 车道管道 | +| 条数 | 理由(截断) | 归属 | +|---|---|---| +| 21 | `dedicated Magma run-ahead lane only` / `dedicated Magma cache lane only` | 车道标记:这两组只在 tier 1 的 inproc 臂跑(§6 的债) | +| 5 | `GL_MAX_IMAGE_SAMPLES is 0, so the conformance case substitutes a plain 2D image` | lavapipe 能力 | +| 5 | `C-1's per-level respecify is consumed by DirectGLES only; backend is DirectVulkan` | Espryt 专属(P3b/P4b) | +| 4 | `DirectGLES only: this scenario is about Espryt's own reachability table` | Espryt 专属 | +| 3 | `three-channel widening is a DirectGLES substitution` | Espryt 专属 | +| 3 | `F-3 is a DirectGLES handle-arm seam` | Espryt 专属 | +| 2 | `the signed-normalized substitution is a DirectGLES fallback` | Espryt 专属 | +| 2 | `subgroup probe requires GL_SUBGROUP_SIZE_KHR in [16, 256]` | lavapipe 能力 | +| **2** | **`object_death is produced by the DirectGLES death-notice ops; DirectVulkan has none until P7`** | **wave 2 包 C 的债,见 §6** | +| 1 | `this driver cannot host separate DEPTH_COMPONENT24 and STENCIL_INDEX8 attachments` | lavapipe 能力(`DepthStencilReadbackMatrixScenario.SeparateDepthAndStencil…`) | +| 2 | `renderer Magma … clips by a DISABLED gl_ClipDistance` / `… regardless of the enables` | 已知 Magma 语义缺口(tier 1 同两条) | +| 2 | `known: a non-trailing unsized array overlaps…` / `two runtime arrays in one block overlap` | 已知(SSBO 声明形状) | +| 1 | `atomic-counter draws do not paint on DirectVulkan yet` | 已知 Magma 缺口 | +| 4 | `this case needs the pinned ON for the whole process` ×3、`MOBILEGL_ASYNC_SHADER_COMPILE is unset` ×1 | 各自专属车道 | +| 5 | `not the strict-arming lane` / `not the counting lane` / `requires the dedicated per-frame stats lane` / `runs only in its own lane` / `optimistic-status quirk` | 各自专属车道 | -**根因,逐行**: +**注意 `DepthStencilReadbackMatrixScenario.SeparateDepthAndStencilAttachmentsAreBothReadable` 是 SKIP 而不是 +红**:审计预测它会撞 `multisample-blit-aspect@P7`,实际上在 lavapipe 上它连 framebuffer 都组不起来,先一步 +skip 了。这就是「主机拿不到那份红名单」的一个具体样本——它需要一台能做 separate D/S 附件的真设备。 -- P1:`MagmaRunAheadScenario::HoldNextBatch` 经 `ArmSplitApplyHoldForTesting()` 把钩子装到 - `MG_Remote::Server::ServerLoopInstance().SetBeforeRetireHookForTesting(&HoldOneAppliedBatch)` - (`Harness/SplitRuntimePeek.cpp:43-50`)——**本进程**的 server loop。spawn/tcp 下 server loop 在另一个 - 进程里,钩子装在一个永不运行的实例上,等待必然超时。 -- P2:`MagmaWireCacheScenario::SetUp` 直接 `ASSERT_EQ(runtime.transportName, "inproc")` - (`MagmaWireCacheScenario.cpp:53`),整条车道读的是**本进程** server 的 view / attachment 身份。 +## 5. 红名单:全量普查在 1530 条里只产出 1 条,而它是 stream 数据面的 -**处置**:两条车道回到**单臂(inproc)注册**,理由写在 CMakeLists 的两段注释里,并在 -`spawn_lane_parity.py` 的 `MAGMA_INPROC_ONLY` 里**具名豁免**(照抄 `MONOLITH_ONLY` 的纪律:宁可点名, -也不放宽容差)。这与本文件已有的四条 DirectGLES 单臂车道(DualBlock / StrictProgramArm / -PersistentMapArm / StrictArming)是同一条规矩:**一个因为「不是它存在的理由」而必然红的条目,比没有这个 -条目更糟**(R-16 的镜像)。 +| 组 | 条数 | 首阻塞 | 分类 | +|---|---|---|---| +| **S1 曝光 texel(tcp / stream 专属)** | 1 | `Scenarios/IterationRPProgram203Scenario.cpp:371: complete Program 203 output differs at 0,0: actual half bits=(0x357a, 0x4b65) golden half bits=(0x3a74, 0x4821); mismatched 1 of 262656 texels`,另有 `:377` 的第二条断言。**两个角色日志里都没有 `Fatal{` / `Refuse{`** | **错误像素**(不是 `@P7` 中止、不是超时、不是管道) | -**由此产生的债(不是本包能关的)**:两进程口径下的 run-ahead 与 cache 身份**今天没有覆盖**。要覆盖,需要 -一个**跨进程**的 hold(server 侧旋钮,而不是函数指针)和一个跨进程的 cache peek。这两件都该由 wave 2-B/C -的 owner 决定要不要做——**本包不擅自做**,只把缺口写在这里。 +**为什么判它是真缺陷而不是车道管道,四条证据**: -## 5. 死亡通知前提(交付 3):修好了,而且当场就有效 +1. **确定性**:tcp 臂连跑 5 次,5 次全红,同一个 texel、同一组 bits。 +2. **只在 tcp**:同一用例在 `DirectVulkan.Split.Full.`(inproc)、`DirectVulkan.Spawn.Full.`(spawn,**数据面 + 是 shm**)与 monolith `DirectVulkan.` 各连跑 5 次,**各 5/5 全绿**。三臂唯一的差别是传输片段, + 而 spawn 与 tcp 的差别只有 `MOBILEGL_IPC_CONTROL=tcp://…` + `MOBILEGL_IPC_DATA=stream`。 + ⇒ **嫌疑落在 stream 数据面,不落在「两进程」本身。** +3. **GLES 的 tcp 车道是绿的**(`integration-tcp` 104/104),同一轮同一台机器 ⇒ 不是 fixture、不是端口、 + 不是 supervisor。 +4. **差的是第 0 号 texel**,而这个位置正是该用例自己打印为 `actualExposureBits` 的**曝光值** + (`IterationRPProgram203Scenario.cpp:363-370`);其余 262655 个 texel 逐位相同 ⇒ 不是整幅画错,是 + **归约/曝光那一条链**上的一个值。 + +**归簇**:不属于 A(UniformManager 对齐)/ B(blit-copy-mip)/ C(顶点 / 死亡表 / resident / 反射)中的任何 +一个——它是 **P6.5 stream 传输 × Magma 归约链**的交叉项。建议作为 **wave 2 的一条独立小项**派给 +stream 数据面的 owner,或先在 wave 1 的设备窗口里确认它在真机 tcp 上是否复现。 + +**本包没有去修它**(超出「只修管道」的授权),也没有把它从普查里排除——它就该红在那里。 + +### 5.1 第一轮(tier 3 带着 `MGITEST_SPLIT_LANE=1`)的 14/15 条红,全部是车道管道,已修 + +留档,因为它们是「普查需要自己的环境」这条结论的证据: + +| 组 | 条数(split/spawn/tcp) | 首阻塞 | 处置 | +|---|---|---|---| +| F1 fixture 记录序号断言 | 13 / 13 / 13 | `Harness/ScenarioFixture.h:90: this case ran in an armed DirectGLES.Split. lane and the client encoder's record ordinal did not move: EmitSeq was 20 at SetUp and is 20 now` | tier 3 不再设 `MGITEST_SPLIT_LANE=1`(§2.1-1) | +| F2 dual-block 负控 | 1 / 1 / 1 | `Scenarios/DualBlockScenario.cpp:63: before.roleSplitActive Actual: false Expected: true … MOBILEGL_IPC_ROLE_SPLIT_STATE is not armed` | tier 3 过滤掉 `DualBlockScenario.*`(§2.1-2) | +| F3 server 计数器未发布 | 0 / 1 / 0 | `Scenarios/CtWireScenario.cpp:131: counters.valid Actual: false Expected: true server control-record telemetry missing` | tier 3 的 CtWire 条目补 `MOBILEGL_TEST_SERVER_COUNTERS=1`(遥测开关,不是断言旋钮) | + +## 6. 死亡通知前提(交付 3):修好了,而且当场就有效 **改动**:`WireTables.cpp` 的安装条件从 - -```cpp -Transport == Spawn && ActiveBackendType == BackendType::DirectGLES && GetStateObjectDeathOps() == nullptr -``` - -去掉中间一条。保留的两条正是 P6.5 原意的两半:`Transport == Spawn` = 「这是没有本地孪生表的远端 client」; -`GetStateObjectDeathOps() == nullptr` = 「谁先装谁算,inproc 保留后端自己的派发器」。 +`Transport == Spawn && ActiveBackendType == DirectGLES && GetStateObjectDeathOps() == nullptr` +去掉中间一条。保留的两条正是 P6.5 原意的两半。 **R-16(安装点是承重的)**:把安装点临时短路掉(`if (false && …)`)重编,两条 **DirectGLES spawn** 死亡用例 立刻红: @@ -148,50 +200,50 @@ CtWireScenario.cpp:246: Failure Expected: (afterCounters.deaths) > (deathsBefor 这正是计划 §1.3 (2) 描述的「静默 `ObjectDeaths=0`」的形状,而车道抓得住它。已还原。 -**Magma 下实际观测到什么**(计划要求「记录你观察到的」):`CtWireScenario` 自己在非 DirectGLES 上 -`GTEST_SKIP`(`:152-155` / `:208-211`),所以门控与信息档里这两条是 **SKIP**,不是 0 也不是绿。 -为了给集成者一个真数,做了一次**临时、未提交**的探针(把那两处 skip 守卫去掉重编,跑完还原并重编): +**Magma 下实际观测到什么**:`CtWireScenario` 自己在非 DirectGLES 上 `GTEST_SKIP`(`:152-155` / `:208-211`), +所以三档里这两条都是 **SKIP**。做了一次**临时、未提交**的探针(去掉那两处 skip 守卫重编,跑完还原并重编): | 臂 | 结果 | |---|---| -| `DirectVulkan.Spawn.Ct.CtWireScenario.{Texture,Framebuffer}Death…` | **两条 PASS**(`deaths > deathsBefore` 成立) | -| `DirectVulkan.Split.Ct.…`(inproc) | **两条 FAIL** | +| `DirectVulkan.Spawn.…Death…`(spawn) | **两条 PASS**(`deaths > deathsBefore` 成立) | +| `DirectVulkan.Split.…Death…`(inproc) | **两条 FAIL** | -也就是说:**本包的前提修复让 Magma 的 spawn / tcp 路径今天就能跨 `object_death`**(对象作为 wire 对象已经 -过线,`MGPipeSlots().FindByLifetimeId` 解析得到句柄),计划里「Magma 下计数可能仍然是 0」的预期只在 -**inproc 臂**成立——inproc 靠的是后端自己的 `StateObjectDeathOps`,而 Magma 还没有那张表(wave 2 包 C)。 +即:**本包的前提修复让 Magma 的 spawn / tcp 路径今天就能跨 `object_death`**;计划里「Magma 下计数可能仍然 +是 0」的预期只在 **inproc 臂**成立(inproc 靠后端自己的 `StateObjectDeathOps`,Magma 还没有那张表 = wave 2 +包 C)。 -→ **给集成者的一条裁定项(ID 待编)**:`CtWireScenario` 的 skip 守卫(`BackendName() != "DirectGLES"`)现在 -**过宽**,可以窄化为「非 DirectGLES **且** transport 非 spawn/tcp 才 skip」,代价是一行,收益是 Magma 两进程 -死亡路径立刻有门。本包**没有**改它:那是 wave 2 包 C 的文件,且改了会让信息档的 inproc 臂变红(需要同时 -决定 inproc 臂怎么处置)。 +→ **裁定项**:`CtWireScenario` 的 skip 守卫(`:152`/`:208`)现在**过宽**,可窄化为「非 DirectGLES **且** +transport 非 spawn/tcp 才 skip」,一行代价,收益是 Magma 两进程死亡路径立刻有门。本包**没有**改它:那是 +wave 2 包 C 的文件,且改了会让 inproc 臂变红(需要同时决定 inproc 臂怎么处置)。 -## 6. CI(交付 4) +## 7. CI -**(a) retrace-split 的三个旋钮**。`test.yml` 的 `retrace-split` 作业「Retrace and validate under -MOBILEGL_TRANSPORT」一步过去**一个 Magma 旋钮都不导出**,而 monolith `retrace` 作业(`:2180-2196`)对 -`minecraft-1.21.4-fabric-iris-iterationrp-in-world × DirectVulkan` 导出三个 iterationRP 修复。已按**逐字 -相同**的 backend+case 守卫补上三个旋钮。`split-matrix` 实测 154 格,含该 case × DirectVulkan × {inproc, -spawn} 两格——也就是这一步过去是唯一**无法**与 monolith 对照的两格。 +**(a) retrace-split 的五个旋钮**(两次提交合起来)。该作业过去**一个 Magma 旋钮都不导出**。现已按与 monolith +`retrace` 作业(`test.yml:2180-2196`)**逐字相同**的守卫补齐: -**(b) 门控标签**。两条新标签首轮全绿,因此按交付要求入门控: +- `MOBILEGL_MAGMA_R11G11B10F_FALLBACK`(全部 DirectVulkan 行) +- `MOBILEGL_MAGMA_DISABLE_BLENDED_DEPTH_WRITE`(`improved-transparency-minecraft-26.3`) +- 三个 iterationRP 修复(`minecraft-1.21.4-fabric-iris-iterationrp-in-world`) -- 新步骤 `Integration-magma-spawn and -tcp - the same cases in two processes (P7 L)`: +`split-matrix` 实测 154 格,含上述 case × DirectVulkan × {inproc, spawn}。`retrace-verify` 按裁定未动。 + +**(b) 门控标签**。两条新标签实测全绿,因此入门控: + +- `Integration-magma-spawn and -tcp - the same cases in two processes (P7 L)`: `ctest -L '^integration-magma-spawn$'` 与 `'^integration-magma-tcp$'`,job 环境与既有 magma-split 一步相同。 -- 新步骤 `Magma application-buffer wire cases must all execute on the spawn and tcp arms`:对 +- `Magma application-buffer wire cases must all execute on the spawn and tcp arms`:对 `integration-magma-{spawn,tcp}-buffers` 按**名字** `require_green` 那 19 条(tcp 臂的必需名单里**显式包含** - `TcpServer.Start` / `TcpServer.Stop`,因为 ctest 会把 fixture 一起列进标签,而 supervisor 没起来的车道对 - 那 19 条无话可说)。 + `TcpServer.Start` / `TcpServer.Stop`)。 -两步都在本机**实跑过**(不只是 `bash -n`):spawn 19/19 + `require-green: 19 PASS, 0 skip, 0 failed`, -tcp 19/19 + `require-green: 21 PASS, 0 skip, 0 failed`。整个 workflow 的 **99 个 `run:` 块**全部 `bash -n` 通过。 +两步都在本机**实跑过**:spawn `19 PASS, 0 skip, 0 failed`,tcp `21 PASS, 0 skip, 0 failed`。整个 workflow 的 +**99 个 `run:` 块**全部 `bash -n` 通过。 -**信息档三条标签刻意不入任何门控步骤**,CMake 注释与上面的 CI 注释都写明了升档规则:一个用例随着**退役它的 -那个提交**从第二档搬进第一档。 +**信息档与全量档共六条标签刻意不入任何门控步骤**;升档规则写在 CMake 注释里:一个用例随着**退役它的那个 +提交**从下一档搬进门控档。 -## 7. 车道自身的 red-once(交付 6) +## 8. 车道自身的 red-once(交付 6) -把 spawn 臂的第二个进程拿掉(`mv build-split/libMobileGLServer.so ...redonce-bak`),三件事同时发生: +把 spawn 臂的第二个进程拿掉(`mv build-split/libMobileGLServer.so ...redonce-bak`): ``` # 门控档 @@ -205,43 +257,57 @@ client log: MG_Remote: the spawn session failed to start (rc=2); MobileGL will N # 信息档 0% tests passed, 3 tests failed out of 3 (DirectVulkan.Spawn.TriangleScenario.*) -# 同一时刻,inproc 臂不受影响(破坏是传输特定的,不是「整个 Magma 挂了」) +# 同一时刻,inproc 臂不受影响(破坏是传输特定的) DirectVulkan.Split.Fm.F1WireScenario.ClearBufferfiPixels ... Passed ``` -还原后两条臂即刻回绿。**注意失败是具名的**:断言文本停在 `eglInitialize failed`(pre-flight 子进程),但 -库自己的通道(私有角色日志)里是上面那条 `refusing` 行——这正是 `split_log_paths.py` 反复强调的 -「ctest 的 transcript 对库输出是 false zero」。 +还原后即刻回绿。**失败是具名的**:ctest 的断言文本停在 `eglInitialize failed`(pre-flight 子进程),而库 +自己的通道(私有角色日志)里是上面那条 `refusing` 行——这正是 `split_log_paths.py` 反复强调的「ctest 的 +transcript 对库输出是 false zero」。 -## 8. 名集合与 parity(交付 7) +## 9. 名集合与 parity(交付 7) ``` $ python3 scripts/ci/spawn_lane_parity.py build-split spawn-lane parity: split 105 (102 comparable), spawn 102 # 与基线逐字相同 integration-tcp parity: spawn 102, tcp 102 # 与基线逐字相同 -magma gated tier: integration-magma-split has 73 case entrie(s), 73 after normalisation -magma gated tier: integration-magma-spawn has 52 case entrie(s), 52 after normalisation -magma gated tier: integration-magma-tcp has 52 case entrie(s), 52 after normalisation -magma gated tier: 21 inproc-only entrie(s) excluded from the comparison by name - (MagmaRunAheadScenario., MagmaWireCacheScenario.) -magma informational tier: integration-magma-all-{split,spawn,tcp} 102 / 102 / 102 after normalisation +magma gated tier: 73 / 52 / 52 after normalisation(21 条 inproc-only 具名豁免) +magma informational tier: 102 / 102 / 102 after normalisation +magma full-suite tier: 510 / 510 / 510 after normalisation RC=0 ``` Magma 档的归一化**只脱臂段**(`..<其余>` → `.<其余>`),**不脱**子车道尾巴: -`RunAhead.Credit1.` 与 `RunAhead.Credit3.` 是同一个用例的两条条目,脱掉尾巴会把它们折成一条,然后报一个 -「数目相等」的假绿。GLES 档保持原样(脱 `F1.` / `Ct.`),数字与基线逐字相同。 +`RunAhead.Credit1.` 与 `RunAhead.Credit3.` 是同一个用例的两条条目。inproc-only 豁免是**逐档**的:门控档里 +`MagmaRunAheadScenario` / `MagmaWireCacheScenario` 只注册在 inproc 臂(§10 的债),全量档里它们三臂都在 +(只是各自 SKIP),所以在全量档豁免它们反而会造出假的 `extra`。 **G14(名字只增不减)**,对 `~/w7/p7-before/ctest-names-split.txt`: ``` -before=4155 after=4565 removed=0 added=410 -added by prefix: DirectVulkan.Spawn. 154 DirectVulkan.Tcp. 154 DirectVulkan.Split. 102 +before=4155 after=6095 removed=0 added=1940 +added by prefix: DirectVulkan.Split. 612 DirectVulkan.Spawn. 664 DirectVulkan.Tcp. 664 ``` -410 = (52 门控 spawn + 102 信息 spawn) + (52 门控 tcp + 102 信息 tcp) + 102 信息 split。**removed = 0。** +1940 = (52+102+510) spawn + (52+102+510) tcp + (102+510) split。**removed = 0。** -## 9. 相邻门(本机实跑,证明没有回归) +## 10. 明写的例外与债 + +**`MagmaRunAheadScenario`(14)与 `MagmaWireCacheScenario`(7)在门控档里只注册 inproc 臂。** 第一次把三臂 +加给全部六条 Magma 车道时,spawn 与 tcp 各红 21 条,两臂逐条相同,**两个角色日志里都没有任何 `Fatal{`**: + +- `MagmaRunAheadScenario.cpp:134: Value of: WaitForSplitApplyHoldForTesting() Actual: false Expected: true` + ——`HoldNextBatch` 经 `ArmSplitApplyHoldForTesting()` 把钩子装到 + `ServerLoopInstance().SetBeforeRetireHookForTesting`(`Harness/SplitRuntimePeek.cpp:43-50`),**本进程**的 + server loop;spawn/tcp 下它在另一个进程里。 +- `MagmaWireCacheScenario.cpp:53: runtime.transportName Which is: "non-monolith" / "inproc"`——`SetUp` 直接 + 断言 inproc。 + +处置:回到单臂注册,理由写进 CMakeLists,并在 `spawn_lane_parity.py` 的 `MAGMA_INPROC_ONLY` 里**具名豁免** +(照抄 `MONOLITH_ONLY` 的纪律)。**债**:两进程口径下的 run-ahead 与 cache 身份**今天没有覆盖**,需要一个 +**跨进程**的 hold(server 侧旋钮)和跨进程 cache peek——归 wave 2-B/C 的 owner 裁定。 + +## 11. 相邻门(本机实跑,证明没有回归) | 门 | 结果 | |---|---| @@ -250,47 +316,40 @@ added by prefix: DirectVulkan.Spawn. 154 DirectVulkan.Tcp. 154 DirectVulkan | `integration-p5f-rsp` 的 `require_green` | `2 PASS, 0 skip, 0 failed` | | `scripts/ci/magma_cache_checks.py --execute`(exact-seven + 环境不变式) | 7/7 `verdict=GREEN` | | `scripts/ci/magma_runahead_checks.py negative --execute` | `run_ahead_0: EXPECTED_RED` → `restored_run_ahead_1: GREEN` | -| `integration-magma-{buffers,runahead,caches}` 锚定标签计数 | 19 / 14 / 7,与基线相同 | +| `integration-magma-{buffers,runahead,caches}` 锚定标签 | 19 / 14 / 7,全绿,与基线相同 | +| 六条 Magma 车道的 ICD 钉(裁定后) | 73/73 条带 `VK_ICD_FILENAMES` 与三个 iterationRP 变量;`DirectGLES.Split.NamedBlit.` 两条**不带** | -## 10. 没有验证的(明写) +## 12. 没有验证的(明写) -- **真机**:一次都没有跑(本包全部在 lavapipe 主机)。出口门 3 的真机 ssim 归 wave 1。 -- **retrace**:没有跑 retrace-split 矩阵,(a) 的三个旋钮只验证了 YAML + shell 语法与 matrix 里确实有那两格, +- **真机**:一次都没有跑(全部在 lavapipe 主机)。出口门 3 的真机 ssim 归 wave 1。**§4 的若干 SKIP(分离 + D/S 附件、subgroup 探针、`GL_MAX_IMAGE_SAMPLES=0`)只有真机才能变成真结果。** +- **retrace**:没有跑 retrace-split 矩阵,五个旋钮只验证了 YAML + shell 语法与 matrix 里确实有那些格, **没有**验证加上旋钮后 `iterationrp × DirectVulkan × {inproc,spawn}` 会变绿或变红。 -- **pull 构建 / G1**:本包只改 CMake 注册、一处 `MOBILEGL_BUILD_DISAGGREGATED` 之外的 client 文件 - (`WireTables.cpp` 在 `MG_Remote` 下,pull 构建不编译它)与 CI/脚本;**没有**重跑 pull `.text` 恒等。 - 合并前请由集成者跑一次 G1。 +- **§5 那条红的根因**:只做到「确定性、tcp/stream 专属、曝光 texel」,没有下钻到具体的记录或回读。 +- **pull 构建 / G1**:本包改的是 CMake 注册、`MG_Remote` 下的一处 client 文件(pull 构建不编译它)与 + CI/脚本;**没有**重跑 pull `.text` 恒等。合并前请由集成者跑一次 G1。 - **`MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT`**:本树为空,`TcpDevice` 臂未配置,Magma **不给** TcpDevice 臂 - (一台手机、串行,主机臂都还没绿之前翻倍没有收益)——这是一个明写的决定,不是遗漏。 -- **信息档在 CI runner 上的耗时**:本机三条信息车道合计 24.5 s(`-j 8`),CI runner 未测。 + (一台手机、串行)——明写的决定,不是遗漏。 +- **CI runner 上的耗时**:本机 tier 3 三条合计约 2 分 6 秒(`-j 8`,其中 tcp 臂 91 s,因 fixture 串行), + CI runner 未测。 -## 11. 给集成者的发现(按重要性) +## 13. 给集成者的发现(按重要性) -1. **出口门 1 的主机半边已经满足,红名单是空的。** 计划把 wave 2 的 A/B/C 三簇建立在「首轮红名单」之上; - 在主机 × lavapipe 口径下没有这样一份名单。`@P7` 的 15 处具名拒绝**没有一处**被这 410 条新条目触发。 - 建议:把「红名单来源」改挂到 wave 1 的真机实验 + retrace 全矩阵 + P3b/P4b 的 ~20 个候选场景普查上, - 并据此重估 wave 2 三簇的规模;本车道的职责改为**回归门**(退役一条,把它从第二档搬进第一档)。 -2. **`CtWireScenario` 的 skip 守卫过宽**(`:152`/`:208`):Magma **spawn/tcp** 的死亡路径今天实测可通 - (§5),只有 inproc 臂还等 wave 2 包 C 的 `StateObjectDeathOps`。一行窄化即可让两进程死亡路径有门。 -3. **两进程 run-ahead / cache 身份今天无覆盖**(§4 的债):需要跨进程 hold 与跨进程 cache peek,属 - wave 2-B/C owner 的裁定。 -4. **既有 Magma 车道不带 ICD 钉**(相邻缺陷,未修):`MGL_ITEST_MAGMA_*_ENVIRONMENT` 家族拼的是 - `${MGL_ITEST_COMMON_ENV}`,**不是** `${MGL_ITEST_VULKAN_ENV}`,所以 monolith `DirectVulkan.` 臂有 - `VK_ICD_FILENAMES` 与 lavapipe 的三个 iterationRP 修复,而 `integration-magma-split` 的 73 条**没有** - (`CMakeLists.txt` 内 Fm / Buffers / RunAhead / Caches / NamedBlit / P5fRsp 六处)。本机只装了 lavapipe - 一个 ICD,所以驱动是同一个,但**三个修复旋钮的取值不同**。本包**没有**改动它们(那会改变 73 条既有条目的 - 环境,超出「含义不变」的承诺);新的 `MGL_ITEST_VULKAN_{SPLIT,SPAWN,TCP}_ENVIRONMENT`(信息档用)按交付 - 要求用了 `${MGL_ITEST_VULKAN_ENV}`。**因此两档之间存在一处已知的环境不对称**,请裁定是把六条车道对齐到 - `VULKAN_ENV`,还是把信息档降回 `COMMON_ENV`。 -5. **`retrace-split` 还缺另外两个 monolith / verify 都有的旋钮**(相邻缺陷,未修): - `MOBILEGL_MAGMA_R11G11B10F_FALLBACK`(monolith `:2180`、verify `:2383` 都有)与 - `MOBILEGL_MAGMA_DISABLE_BLENDED_DEPTH_WRITE`(`:2195` / `:2387`)。交付只点名了 iterationrp 的三个, - 故只补了三个;这两个同样让 split 与 monolith 不可比。 +1. **出口门 1 的主机半边只欠一条,而且不是 `@P7`。** 全量普查 1530 条里 **0 条**触发树上 15 处 `@P7` 具名 + 拒绝;唯一的红是 §5 的 stream 曝光 texel。计划把 wave 2 的 A/B/C 三簇建立在「首轮红名单」之上——这份 + 名单在主机 × lavapipe 口径下是空的。**建议**:把红名单来源改挂到 wave 1 真机 + retrace 全矩阵 + + P3b/P4b 场景普查;本车道的职责改为**回归门**,并把 §5 作为 stream 数据面的独立小项派出去。 +2. **§5 的 stream 曝光 texel**:确定性、tcp 专属、与 A/B/C 三簇都不同族。需要一位 owner。 +3. **`CtWireScenario` 的 skip 守卫过宽**(`:152`/`:208`):Magma **spawn/tcp** 的死亡路径今天实测可通(§6), + 只有 inproc 臂还等 wave 2 包 C 的 `StateObjectDeathOps`。一行窄化即可让两进程死亡路径有门。 +4. **两进程 run-ahead / cache 身份今天无覆盖**(§10 的债)。 +5. **tier 3 放弃了两条自证**(记录过线证明、tcp 拓扑证明,§2.1-1)。若将来要把某条全量用例升进门控档, + 必须连同 `MGITEST_SPLIT_LANE=1` 一起升——门控档的价值有一半在这两条自证上。 6. **`DUALBLOCK_ALLOWED_SKIPS` 只收录 Split 拼写**(`split_log_paths.py:156-157`)。如果将来把 magma-spawn/-tcp 加进 dual-block 普查的选择式,需要同时补 `DirectVulkan.{Spawn,Tcp}.Fm.ClipDistance…` 两条,否则那一步会以「unexpected skip」红。 -## 12. 复现 +## 14. 复现 ```bash cd ~/w7/p7-lane @@ -301,9 +360,13 @@ cmake -S . -B build-split -DMOBILEGL_BUILD_INTEGRATION_TEST=ON \ ninja -C build-split -j 20 python3 scripts/ci/spawn_lane_parity.py build-split cd build-split +# 门控档(CI 口径) MOBILEGL_ITEST_REQUIRE_GPU=1 MOBILEGL_IPC_STRICT_ERRORS=1 MOBILEGL_IPC_ROLE_SPLIT_STATE=1 \ ctest -L '^integration-magma-spawn$' --no-tests=error -j 2 --output-on-failure -MOBILEGL_ITEST_REQUIRE_GPU=1 MOBILEGL_IPC_STRICT_ERRORS=1 MOBILEGL_IPC_ROLE_SPLIT_STATE=1 \ - ctest -L '^integration-magma-tcp$' --no-tests=error -j 2 --output-on-failure -MOBILEGL_ITEST_REQUIRE_GPU=1 ctest -L '^integration-magma-all-spawn$' --no-tests=error -j 8 --output-on-failure +# 全量普查(一条一条跑,-j 8) +MOBILEGL_ITEST_REQUIRE_GPU=1 ctest -L '^integration-magma-full-split$' --no-tests=error -j 8 --output-on-failure +MOBILEGL_ITEST_REQUIRE_GPU=1 ctest -L '^integration-magma-full-spawn$' --no-tests=error -j 8 --output-on-failure +MOBILEGL_ITEST_REQUIRE_GPU=1 ctest -L '^integration-magma-full-tcp$' --no-tests=error -j 8 --output-on-failure +# §5 的那一条 +MOBILEGL_ITEST_REQUIRE_GPU=1 ctest -V -R '^DirectVulkan\.Tcp\.Full\.IterationRPProgram203Scenario\.' ``` diff --git a/scripts/ci/spawn_lane_parity.py b/scripts/ci/spawn_lane_parity.py index 0cbe04b2..74035881 100644 --- a/scripts/ci/spawn_lane_parity.py +++ b/scripts/ci/spawn_lane_parity.py @@ -75,7 +75,7 @@ def lane_cases(build_dir, label): return {m.group(1) for m in CASE.finditer(out)} -def compare_arms(build_dir, tier, labels): +def compare_arms(build_dir, tier, labels, inproc_only=()): """The three arms of one tier must name the same set after the arm segment comes off. Returns True on failure, the way main() below counts them.""" @@ -96,10 +96,10 @@ def compare_arms(build_dir, tier, labels): failed = False reference = "split" comparable = {k for k in sets[reference] - if not any(only in k for only in MAGMA_INPROC_ONLY)} + if not any(only in k for only in inproc_only)} if len(comparable) != len(sets[reference]): print(f"{tier}: {len(sets[reference]) - len(comparable)} inproc-only entrie(s) excluded " - f"from the comparison by name ({', '.join(MAGMA_INPROC_ONLY)})") + f"from the comparison by name ({', '.join(inproc_only)})") for arm, keys in sets.items(): if arm == reference: continue @@ -157,14 +157,29 @@ def main(): failed = True # P7 package L, exit gate 1's half of the same question: the Magma arms. + # THE EXCLUSION IS PER TIER, not global. In the GATED tier the two scenarios are registered + # on the inproc arm ALONE (the CMakeLists says why), so they are absent from the other arms + # and have to come off the reference set. In the FULL-SUITE census they are registered on + # every arm - it is a whole-binary filter, and there they simply SKIP for want of their + # lane marker - so excluding them there would turn a present-on-all-arms case into a + # spurious "extra". failed |= compare_arms(args.build_dir, "magma gated tier", {"split": "integration-magma-split", "spawn": "integration-magma-spawn", - "tcp": "integration-magma-tcp"}) + "tcp": "integration-magma-tcp"}, + inproc_only=MAGMA_INPROC_ONLY) failed |= compare_arms(args.build_dir, "magma informational tier", {"split": "integration-magma-all-split", "spawn": "integration-magma-all-spawn", "tcp": "integration-magma-all-tcp"}) + # Tier 3, the whole-suite census. It is expected to be RED and is in no gating step - but + # its three arms must still name the same set, because the census's whole value is that a + # case red on spawn and green on inproc is a two-process fact, and that comparison needs + # both arms to have run the same case. + failed |= compare_arms(args.build_dir, "magma full-suite tier", + {"split": "integration-magma-full-split", + "spawn": "integration-magma-full-spawn", + "tcp": "integration-magma-full-tcp"}) return 1 if failed else 0