[MG_IntegrationTest, CI] (P7): the split arms take a backend, so Magma has two-process lanes at last

P7 exit gate 1 asks for integration green "under Magma push and split". Until now it was not
merely unmet, it was UNMEASURABLE: every arm of mgl_itest_register_split_arms hardcoded
MOBILEGL_BACKEND_TYPE=DirectGLES (:2002/:2025/:2031) and MGL_ITEST_MAGMA_WIRE_ENVIRONMENT
hardcoded MOBILEGL_TRANSPORT=inproc (:2456), so the shared integration-split / -spawn / -tcp
labels held ZERO DirectVulkan entries and the 73 integration-magma-split cases only ever ran in
one process.

The registration macro now takes the backend as its first argument; the old name is a thin
wrapper, so all 32 call sites are untouched and every DirectGLES name, label and private log
path is byte-for-byte what it was. Two tiers come out of it, and the CMake comment states both:

  * GATED - integration-magma-{split,spawn,tcp}. The six hand-laid Magma lanes (Fm, Buffers,
    RunAhead, Caches, NamedBlit, P5fRsp) grow arms through one shared shape macro; the inproc
    arm keeps its names, its labels and its log paths, so the CI steps and the two magma_*
    checker scripts that name them by hand keep working unchanged.
  * INFORMATIONAL - integration-magma-all-{split,spawn,tcp}, in no gating step. Every scenario
    the split arms run, on Magma, on all three transports, generated by REPLAYING the macro's
    recorded call list - so a scenario added to the split arms tomorrow joins the Magma census
    the same day. Its job is to be able to go red while CI stays green; a case moves up into the
    gated tier with the commit that retires its blocker.

The label spellings are chosen against ctest -L's regex (ID-131 again): the tier word goes in
the MIDDLE, because integration-magma-spawn-all WOULD have been selected by
-L integration-magma-spawn and pulled ~100 expected-red entries into a gated lane. Sub-labels
mirror it: the inproc arm keeps integration-magma-buffers, the others put the arm word first.

MagmaRunAheadScenario and MagmaWireCacheScenario stay on the inproc arm alone, and that is
MEASURED rather than assumed: with all three arms registered, all 21 entries red on spawn and
tcp with no Fatal in either role log - the first arms its hold through
ServerLoopInstance().SetBeforeRetireHookForTesting, a hook on THIS process's server loop, and
the second asserts transportName == "inproc" in its SetUp. Both are named in the CMakeLists and
in spawn_lane_parity.py rather than allowed to widen a tolerance.

split_log_paths.py's is_split prefixes gain DirectVulkan.Spawn. / .Tcp. - on those arms two
processes append to one path, so a shared log does not merely blur attribution, it interleaves
two sessions. spawn_lane_parity.py gains the Magma dimension, normalising only the ARM segment:
RunAhead.Credit1. and .Credit3. are two entries of one case and a tail-stripping normaliser
would fold them together and then report an equal-sized set that had lost one.

Measured on this tree (lavapipe): magma-split 73 unchanged and green, magma-spawn 52/52,
magma-tcp 52/52, the three informational lanes 102 each, GLES split 186 / spawn 102 / tcp 104
all unchanged and green. G14 against ~/w7/p7-before: 4155 to 4565, removed 0, added 410.
This commit is contained in:
2026-09-22 14:24:19 -04:00
parent 9e8fdacd21
commit 3d9a38a979
3 changed files with 446 additions and 68 deletions
+349 -67
View File
@@ -2053,6 +2053,103 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
"MGITEST_SPLIT_LANE=1" "MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# ---- P7 package L: THE SAME THREE ARMS FOR MAGMA ----------------------------------------
#
# The three lists above are the DirectGLES half of a dimension that had only one value. P7
# exit gate 1 asks for integration AND trace green "under Magma push and split", and until
# this package the shared labels `integration-split` / `-spawn` / `-tcp` held ZERO
# DirectVulkan entries: every arm of mgl_itest_register_split_arms hardcoded
# MOBILEGL_BACKEND_TYPE=DirectGLES and MGL_ITEST_MAGMA_WIRE_ENVIRONMENT hardcoded
# MOBILEGL_TRANSPORT=inproc, so the gate was not merely unmet, it was UNMEASURABLE.
#
# THE ONE DIFFERENCE FROM THE GLES TRIO IS ${MGL_ITEST_VULKAN_ENV}, AND IT IS NOT COSMETIC.
# That list carries VK_ICD_FILENAMES and, on lavapipe, the three iterationRP repairs the
# monolith `DirectVulkan.` arm has been pinned to since they were added (see its definition
# near the top of this file). A DirectVulkan lane that appended ${MGL_ITEST_COMMON_ENV}
# instead would run against whatever ICD the loader found first, which is exactly how a lane
# measures a different driver from the one the gate it mirrors measures.
#
# MOBILEGL_ITEST_REQUIRE_GPU=1 IS PINNED, as the existing Magma lanes pin it: on a host with
# no usable Vulkan every one of these entries would otherwise SKIP, and a lane that skipped
# everything and a lane that passed everything are the same green in ctest.
mgl_itest_join_environment(MGL_ITEST_VULKAN_SPLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_SPAWN_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_TCP_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_SPLIT_LANE=1" "MGITEST_TCP_LANE=1" "MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
# THE TRANSPORT DIMENSION ON ITS OWN, for the Magma lanes further down this file that already
# have an environment of their OWN FLAVOUR (strict + dual-block state, run-ahead credits,
# cache pinning) and need only the transport half re-stated per arm. Kept beside the joined
# lists above so there is ONE place that says what "the spawn arm" and "the tcp arm" mean.
set(MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
set(MGL_ITEST_SPAWN_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}")
set(MGL_ITEST_TCP_ARM_TRANSPORT_ENV "MOBILEGL_TRANSPORT=spawn"
"MOBILEGL_IPC_CONTROL=${MOBILEGL_ITEST_TCP_ENDPOINT}" "MOBILEGL_IPC_DATA=stream"
"MOBILEGL_IPC_REQUIRE_SAME_BUILD=1" "MOBILEGL_IPC_LOG_FORWARD=1" "MOBILEGL_IPC_TOKEN="
"MGITEST_TCP_LANE=1")
# ---- P7 package L: ONE SHAPE FOR EVERY MAGMA LANE'S THREE ARMS --------------------------
#
# The gated Magma tier is six hand-laid blocks (Fm, Buffers, RunAhead, Caches, NamedBlit,
# P5fRsp) because each carries a flavour of its own. What they share is the ARM: the same
# three transports, the same tcp fixture, the same label and log-name arithmetic. This macro
# is that shared half, so a seventh block gets its arms right by calling one line.
#
# Sets, for the arm it is given:
# mglItestArmLower split | spawn | tcp
# mglItestArmLogTag "" on the inproc arm, "-spawn"/"-tcp" on the others - THE
# INPROC ARM'S PRIVATE LOG PATHS DO NOT MOVE. magma_cache_checks
# and magma_runahead_checks name entries and re-derive their logs
# from discovery, and P6.5's device evidence cites these paths.
# mglItestArmProperties the tcp fixture + resource lock; empty otherwise
# mglItestArmTransportEnv the arm's transport pins, to append to the lane's flavour
# mglItestMagmaLabels "integration-magma-<arm>" plus one label per WORD in ARGN
#
# THE SUB-LABEL SPELLING IS ASYMMETRIC ON PURPOSE. On the inproc arm a word keeps its
# historical name (`integration-magma-buffers`); on the others the ARM comes first
# (`integration-magma-spawn-buffers`). `ctest -L` is a regex, so the obvious
# `integration-magma-buffers-spawn` would be SELECTED by the CI step that runs
# `-L integration-magma-buffers` and require_greens its nineteen inproc entries by name -
# the lane would red on "required green entries differ" the day this package landed.
macro(mgl_itest_magma_arm_shape mglItestArm)
string(TOLOWER "${mglItestArm}" mglItestArmLower)
set(mglItestArmProperties)
set(mglItestArmLogTag "")
set(mglItestArmTransportEnv ${MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV})
if("${mglItestArm}" STREQUAL "Spawn")
set(mglItestArmTransportEnv ${MGL_ITEST_SPAWN_ARM_TRANSPORT_ENV})
set(mglItestArmLogTag "-spawn")
elseif("${mglItestArm}" STREQUAL "Tcp")
set(mglItestArmTransportEnv ${MGL_ITEST_TCP_ARM_TRANSPORT_ENV})
set(mglItestArmLogTag "-tcp")
set(mglItestArmProperties FIXTURES_REQUIRED mobilegl-tcp RESOURCE_LOCK mobilegl-tcp)
endif()
set(mglItestMagmaLabels "integration-magma-${mglItestArmLower}")
foreach(mglItestWord IN ITEMS ${ARGN})
if("${mglItestArm}" STREQUAL "Split")
set(mglItestMagmaLabels "${mglItestMagmaLabels}\\;integration-magma-${mglItestWord}")
else()
set(mglItestMagmaLabels
"${mglItestMagmaLabels}\\;integration-magma-${mglItestArmLower}-${mglItestWord}")
endif()
endforeach()
endmacro()
set(MGL_ITEST_MAGMA_ARMS Split Spawn Tcp)
# scenarioFilter, a PREFIX TAIL (empty for most; "F1." and "Ct." for the two per-slot loops,
# which name their sub-lane in the test name), then zero or more EXTRA LABEL STEMS. A stem is
# suffixed with the arm's own name (`integration-clientarrays` becomes `-split` on one arm and
@@ -2066,10 +2163,56 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
set(MGL_SPLIT_ARM_TESTS "")
set(MGL_SPLIT_ARM_TEST_LISTS "")
set(MGL_SPLIT_ARM_INDEX 0)
macro(mgl_itest_register_split_arms scenarioFilter prefixTail)
set(mglItestArms Split Spawn Tcp)
if(MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT)
list(APPEND mglItestArms TcpDevice)
set(MGL_SPLIT_ARM_CALLS "")
# ---- P7 package L: THE BACKEND IS NOW A PARAMETER, AND THE TWO TIERS IT REGISTERS -------
#
# TIER 1, GATED. DirectGLES keeps every label it had - `integration-gpu`,
# `integration-{split,spawn,tcp,tcp-device}` and the caller's extra stems - so the sets CI
# gates on and the names G14 ratchets are byte-for-byte what they were. Magma's own gated
# tier is `integration-magma-{split,spawn,tcp}`, laid out by hand further down this file
# because each of those lanes carries a FLAVOUR (strict + dual-block state, run-ahead
# credits, cache pinning) that no shared filter can express.
#
# TIER 2, INFORMATIONAL, AND THAT IS THE POINT. DirectVulkan through THIS macro registers
# `integration-magma-all-{split,spawn,tcp}`: every scenario the split arms run, on Magma, on
# all three transports. It is deliberately in NO CI gating step. P7's exit gate 1 needs a
# lane that can be RED - the first run's red list IS the work list wave 2 clusters A/B/C
# divide up - and a red list is worthless if the only way to record it is to break the
# build's green. When a cluster retires its share, its cases move from this tier into the
# gated one, and CI stays honest at every step in between.
#
# THE LABEL SPELLINGS ARE CHOSEN AGAINST `ctest -L`'s REGEX MATCH (ID-131's rule, which this
# file has paid for twice). `-L integration-magma-spawn` must NOT select this tier, so the
# tier's word goes in the MIDDLE - `integration-magma-all-spawn` does not contain
# `integration-magma-spawn` as a substring, while the obvious `integration-magma-spawn-all`
# does and would have quietly pulled ~100 expected-red entries into the gated lane. Checked
# in both directions for all six spellings.
#
# NO `integration-gpu` ON THE MAGMA ARMS, deliberately: that label is a hard CI gate and the
# existing Magma split entries do not carry it either. NO EXTRA LABEL STEMS either - a stem
# like `integration-clientarrays` would produce `integration-clientarrays-spawn`, which is
# the label the DirectGLES spawn arm already owns, and one `ctest -L` would then run two
# backends under one name.
#
# NO TcpDevice ARM ON MAGMA: the device endpoint is one phone, run serially, and doubling
# its matrix before the host lane is even green buys nothing. Stated rather than implied.
macro(mgl_itest_register_split_arms_for_backend mglItestBackend scenarioFilter prefixTail)
# QUOTED DEREFERENCE, NOT A BARE NAME: a macro parameter is a textual substitution and
# not a variable, so `if(mglItestBackend STREQUAL ...)` would compare the literal string
# "mglItestBackend" and take the else branch on every call.
if("${mglItestBackend}" STREQUAL "DirectGLES")
set(mglItestEnvStem GLES)
set(mglItestLaneStem "integration")
set(mglItestSharedLabels "integration-gpu\\;")
set(mglItestArms Split Spawn Tcp)
if(MOBILEGL_ITEST_TCP_DEVICE_ENDPOINT)
list(APPEND mglItestArms TcpDevice)
endif()
else()
set(mglItestEnvStem VULKAN)
set(mglItestLaneStem "integration-magma-all")
set(mglItestSharedLabels "")
set(mglItestArms Split Spawn Tcp)
endif()
foreach(mglItestArm IN LISTS mglItestArms)
string(TOLOWER "${mglItestArm}" mglItestArmLower)
@@ -2081,7 +2224,7 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
set(mglItestArmLower tcp-device)
set(mglItestArmProperties RESOURCE_LOCK mobilegl-tcp-device)
endif()
set(mglItestArmLabels "integration-gpu\\;integration-${mglItestArmLower}")
set(mglItestArmLabels "${mglItestSharedLabels}${mglItestLaneStem}-${mglItestArmLower}")
foreach(mglItestExtra IN ITEMS ${ARGN})
set(mglItestArmLabels "${mglItestArmLabels}\\;${mglItestExtra}-${mglItestArmLower}")
endforeach()
@@ -2095,14 +2238,14 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
# IT MATTERS MORE ON THE SPAWN ARM: there TWO PROCESSES append to the path, so two
# entries sharing one file is not merely ambiguous, it interleaves two sessions.
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.${mglItestArm}.${prefixTail}"
TEST_PREFIX "${mglItestBackend}.${mglItestArm}.${prefixTail}"
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
TEST_FILTER "${scenarioFilter}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${mglItestArmLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_GLES_${mglItestArmUpper}_ENVIRONMENT}"
ENVIRONMENT "${MGL_ITEST_${mglItestEnvStem}_${mglItestArmUpper}_ENVIRONMENT}"
${mglItestArmProperties}
)
list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}")
@@ -2110,6 +2253,23 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
endforeach()
endmacro()
# THE NAME EVERY EXISTING CALL SITE USES, unchanged in signature so that this package adds a
# dimension without touching one registration. It also RECORDS its call, which is what makes
# tier 2 structural rather than maintained: the informational Magma tier at the end of this
# file replays the recorded list, so a scenario added to the split arms tomorrow joins the
# Magma census the same day and nobody has to remember a second edit. `-` stands for an empty
# prefix tail, because a CMake list cannot tell "one empty element" from "no elements".
macro(mgl_itest_register_split_arms scenarioFilter prefixTail)
if("${prefixTail}" STREQUAL "")
set(mglItestRecordedTail "-")
else()
set(mglItestRecordedTail "${prefixTail}")
endif()
list(APPEND MGL_SPLIT_ARM_CALLS "${scenarioFilter}|${mglItestRecordedTail}")
mgl_itest_register_split_arms_for_backend(DirectGLES "${scenarioFilter}" "${prefixTail}"
${ARGN})
endmacro()
mgl_itest_register_split_arms("ClearThenReadPixelsScenario.*" "")
mgl_itest_register_split_arms("TriangleScenario.*" "")
mgl_itest_register_split_arms("PersistentCoherentMapScenario.*" "")
@@ -2470,38 +2630,50 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
mgl_itest_register_split_arms("F1WireScenario.${f1Slot}Pixels" "F1.")
endforeach()
# P5f fm: the framebuffer/copy/mipmap verbs now consume server records on Magma too.
mgl_itest_join_environment(MGL_ITEST_MAGMA_WIRE_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
#
# P7 package L: THE SAME CASES ON ALL THREE TRANSPORTS. The flavour is everything this lane
# is except the transport, which the arm now supplies - so the inproc arm is byte-for-byte
# the lane P6.5 left green (same names, same labels, same log paths) and the two new arms
# differ from it in exactly one dimension. That is what makes a red here readable: it is a
# TRANSPORT fact, because nothing else changed.
set(MGL_ITEST_MAGMA_WIRE_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# Every entry here is green, R11F_G11F_B10F packed-float mip generation included: the GPU
# shader blit retires the named native-format refusal, so GenerateMipmapPackedFloatPixels
# carries its siblings' label and their pixels assertion.
foreach(fmSlot ComputeImageStoreThroughViewPreservesOtherRootLayer EnabledVertexBufferDrawKeepsNamedP7Fatal SrgbDrawTracksFramebufferConversion Texture1DFramebufferClearPixels VertexIdSamplerAndScalarUniformPixels ComputeImageStoreFramebufferPixels PartialTextureUploadPreservesGpuClearPixels TextureViewClearTargetsItsRootMipAndLayer ClearBufferfiPixels ClearBufferfvPixels ClearBufferivPixels ClearBufferuivPixels ClearNamedFramebufferfiPixels ClearNamedFramebufferfvPixels ClearNamedFramebufferivPixels ClearNamedFramebufferuivPixels CopyTexImage2DPixels CopyTexSubImage2DPixels GenerateMipmapPixels GenerateMipmapPackedFloatPixels GenerateMipmapDepthPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.Fm."
TEST_FILTER "F1WireScenario.${fmSlot}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-magma-split"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_MAGMA_WIRE_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm-${fmSlot}.log")
endforeach()
foreach(fmCase ClipDistanceScenario.AnEnabledClipDistanceRemovesTheNegativeHalf
ClipDistanceScenario.ADisabledClipDistanceRemovesNothing
ClipDistanceScenario.TheEnablesAreIndependentPerDistance
CopyImageLayeredScenario.ArrayToArrayCopiesEverySlice
CopyImageLayeredScenario.ArrayToArrayHonoursDifferentLayerOffsets
CopyImageLayeredScenario.VolumeToVolumeHonoursNonZeroZ
CopyImageLayeredScenario.VolumeToVolumeAtNonZeroMipLevel
CopyImageLayeredScenario.ArrayToVolumeCopiesEverySlice
CopyImageLayeredScenario.VolumeToArrayCopiesEverySlice)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.Fm."
TEST_FILTER "${fmCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-magma-split" TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_MAGMA_WIRE_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm-${fmCase}.log")
# Every entry here is green on the inproc arm, R11F_G11F_B10F packed-float mip generation
# included: the GPU shader blit retires the named native-format refusal, so
# GenerateMipmapPackedFloatPixels carries its siblings' label and their pixels assertion.
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(mglItestMagmaWireEnvironment
${MGL_ITEST_MAGMA_WIRE_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(fmSlot ComputeImageStoreThroughViewPreservesOtherRootLayer EnabledVertexBufferDrawKeepsNamedP7Fatal SrgbDrawTracksFramebufferConversion Texture1DFramebufferClearPixels VertexIdSamplerAndScalarUniformPixels ComputeImageStoreFramebufferPixels PartialTextureUploadPreservesGpuClearPixels TextureViewClearTargetsItsRootMipAndLayer ClearBufferfiPixels ClearBufferfvPixels ClearBufferivPixels ClearBufferuivPixels ClearNamedFramebufferfiPixels ClearNamedFramebufferfvPixels ClearNamedFramebufferivPixels ClearNamedFramebufferuivPixels CopyTexImage2DPixels CopyTexSubImage2DPixels GenerateMipmapPixels GenerateMipmapPackedFloatPixels GenerateMipmapDepthPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "F1WireScenario.${fmSlot}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm${mglItestArmLogTag}-${fmSlot}.log")
endforeach()
foreach(fmCase ClipDistanceScenario.AnEnabledClipDistanceRemovesTheNegativeHalf
ClipDistanceScenario.ADisabledClipDistanceRemovesNothing
ClipDistanceScenario.TheEnablesAreIndependentPerDistance
CopyImageLayeredScenario.ArrayToArrayCopiesEverySlice
CopyImageLayeredScenario.ArrayToArrayHonoursDifferentLayerOffsets
CopyImageLayeredScenario.VolumeToVolumeHonoursNonZeroZ
CopyImageLayeredScenario.VolumeToVolumeAtNonZeroMipLevel
CopyImageLayeredScenario.ArrayToVolumeCopiesEverySlice
CopyImageLayeredScenario.VolumeToArrayCopiesEverySlice)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm."
TEST_FILTER "${fmCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
${mglItestArmProperties}
ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-fm${mglItestArmLogTag}-${fmCase}.log")
endforeach()
endforeach()
endif()
@@ -2509,12 +2681,16 @@ endif()
# strict field checks forced on. Existing public scenarios supply offset, mutation,
# persistent-map, growth and indirect coverage; no copied backend implementation.
if (MOBILEGL_BUILD_DISAGGREGATED)
mgl_itest_join_environment(MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
set(MGL_ITEST_MAGMA_BUFFER_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_ADOPT_TIER=2" "MGITEST_PERSISTENT_MAP_ARM=emulated"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
mgl_itest_magma_arm_shape(${mglItestArm} buffers)
mgl_itest_join_environment(MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT
${MGL_ITEST_MAGMA_BUFFER_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(bufferCase
F1WireScenario.EnabledVertexBufferDrawKeepsNamedP7Fatal
F1WireScenario.UniformBufferRangeAndRebindPixels
@@ -2536,12 +2712,14 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
PersistentCoherentMapScenario.AWriteAfterAFrameBoundaryReachesTheNextFramesDraw
StorageBufferRegrowScenario.AGrownStoreIsVisibleThroughItsExistingIndexedBinding)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.Buffers."
TEST_PREFIX "DirectVulkan.${mglItestArm}.Buffers."
TEST_FILTER "${bufferCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-magma-split\;integration-magma-buffers"
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-buffers-${bufferCase}.log")
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_BUFFER_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-buffers${mglItestArmLogTag}-${bufferCase}.log")
endforeach()
endforeach()
endif()
@@ -2550,15 +2728,30 @@ endif()
# fails rather than turning this dedicated lane into a skip or a lockstep pass.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaRunAheadScenario.cpp)
# P7 package L: THE INPROC ARM ALONE, AND IT IS A PROPERTY OF THE SCENARIO, NOT A GAP.
# MagmaRunAheadScenario::HoldNextBatch arms the hold through
# ServerLoopInstance().SetBeforeRetireHookForTesting (Harness/SplitRuntimePeek.cpp:43-50) -
# a hook on THIS PROCESS's server loop. Under spawn or tcp the server loop is in another
# process, so the hook is installed on a loop that never runs and the wait times out with
# "the clear waited for apply instead of returning while its server batch was held".
# MEASURED, not assumed: registering all three arms made all 14 entries red on both new
# arms, with that sentence and no Fatal in either role log. An entry that cannot pass for a
# reason that is not the subject of its lane is the mirror image of R-16's rule, and this
# file already keeps four DirectGLES lanes (DualBlock, StrictProgramArm, PersistentMapArm,
# StrictArming) on one arm for exactly this reason. The two-process reading of run-ahead
# needs a cross-process hold - a server-side knob, not a function pointer - and that is
# named in this package's report as a debt rather than left as a red nobody can act on.
foreach(credit 1 3)
foreach(mglItestArm IN ITEMS Split)
mgl_itest_magma_arm_shape(${mglItestArm} runahead)
mgl_itest_join_environment(MGL_ITEST_MAGMA_RUNAHEAD_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_RUN_AHEAD=1" "MOBILEGL_IPC_PRESENT_CREDIT=${credit}"
"MOBILEGL_IPC_SPIN_US=0" "MOBILEGL_IPC_ADOPT_TIER=2"
"MGITEST_MAGMA_RUNAHEAD_LANE=1" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV} ${mglItestArmTransportEnv})
foreach(runAheadCase
QueuedBufferVersionsAndDeletedNameReuseKeepTheirPixels
QueuedProgramRebindsKeepEachUniformSnapshot
@@ -2568,13 +2761,15 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
GpuClearSurvivesTheFirstStorageImageUpgrade
PresentCreditActuallyParksTheClientAtItsConfiguredLimit)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.RunAhead.Credit${credit}."
TEST_PREFIX "DirectVulkan.${mglItestArm}.RunAhead.Credit${credit}."
TEST_FILTER "MagmaRunAheadScenario.${runAheadCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-magma-split\;integration-magma-runahead"
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_MAGMA_RUNAHEAD_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-runahead-credit${credit}-${runAheadCase}.log")
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_RUNAHEAD_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-runahead${mglItestArmLogTag}-credit${credit}-${runAheadCase}.log")
endforeach()
endforeach()
endforeach()
endif()
@@ -2583,14 +2778,23 @@ endif()
# retain these names but skip outside this dedicated, strict inproc environment.
if (MOBILEGL_BUILD_DISAGGREGATED)
target_sources(MobileGLIntegrationTest PRIVATE Scenarios/MagmaWireCacheScenario.cpp)
mgl_itest_join_environment(MGL_ITEST_MAGMA_CACHES_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MOBILEGL_TRANSPORT=inproc"
set(MGL_ITEST_MAGMA_CACHES_FLAVOUR_ENV
"MOBILEGL_BACKEND_TYPE=DirectVulkan"
"MOBILEGL_IPC_ROLE_SPLIT_STATE=1" "MOBILEGL_IPC_STRICT_ERRORS=1"
"MOBILEGL_IPC_RUN_AHEAD=1" "MOBILEGL_IPC_PRESENT_CREDIT=3"
"MOBILEGL_IPC_SPIN_US=0" "MOBILEGL_IPC_ADOPT_TIER=2"
"MGITEST_MAGMA_CACHES_LANE=1" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_ITEST_REQUIRE_GPU=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
# P7 package L: THE INPROC ARM ALONE, for the run-ahead lane's reason one step more
# explicit - MagmaWireCacheScenario::SetUp asserts `runtime.transportName == "inproc"`
# outright (MagmaWireCacheScenario.cpp:53), because the whole lane reads the SERVER's own
# view and attachment identity out of this process. MEASURED: all 7 entries red on both new
# arms with `Which is: "non-monolith" ... "inproc"` and no Fatal in either role log.
foreach(mglItestArm IN ITEMS Split)
mgl_itest_magma_arm_shape(${mglItestArm} caches)
mgl_itest_join_environment(MGL_ITEST_MAGMA_CACHES_ENVIRONMENT
${MGL_ITEST_MAGMA_CACHES_FLAVOUR_ENV} ${mglItestArmTransportEnv})
foreach(cacheCase
SamplerSwizzleAtoBtoAKeepsEachQueuedPixel
SamplerRespecifyKeepsOldAndNewNativeImages
@@ -2600,12 +2804,14 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
FramebufferSrgbPolicyAtoBtoAUsesDistinctFormats
FramebufferRespecifyRebindsTheNewNativeImage)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.Caches."
TEST_PREFIX "DirectVulkan.${mglItestArm}.Caches."
TEST_FILTER "MagmaWireCacheScenario.${cacheCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "integration-magma-split\;integration-magma-caches"
PROPERTIES LABELS "${mglItestMagmaLabels}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_MAGMA_CACHES_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-caches-${cacheCase}.log")
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_MAGMA_CACHES_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/magma-caches${mglItestArmLogTag}-${cacheCase}.log")
endforeach()
endforeach()
endif()
@@ -2630,10 +2836,19 @@ endif()
# The separate spelling also avoids ctest's substring label match (see below).
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(namedBlitBackend DirectGLES DirectVulkan)
# P7 package L: the Magma half gets the three arms; the Espryt half stays inproc-only,
# because its spawn and tcp coverage of this scenario comes from the F1. blocks the
# registration macro already emits, and a second copy would only double the count.
set(namedBlitArms Split)
if (namedBlitBackend STREQUAL "DirectVulkan")
set(namedBlitArms ${MGL_ITEST_MAGMA_ARMS})
endif()
foreach(mglItestArm IN LISTS namedBlitArms)
mgl_itest_magma_arm_shape(${mglItestArm})
mgl_itest_join_environment(MGL_ITEST_NAMED_BLIT_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=${namedBlitBackend}" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_BACKEND_TYPE=${namedBlitBackend}"
"MOBILEGL_ITEST_REQUIRE_GPU=1" "MGITEST_SPLIT_LANE=1"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV} ${mglItestArmTransportEnv})
# THE LABEL IS `integration-magma-split` AND NOT `integration-split-magma`, and that is not
# a preference: `ctest -L` takes a REGEX, not an exact name, so `-L integration-split`
# MATCHES a label spelled `integration-split-magma` as a substring. The obvious name would
@@ -2641,19 +2856,21 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
# split that looks done and is not. Measured: with that spelling
# `ctest -N -L integration-split` still listed both DirectVulkan entries.
if (namedBlitBackend STREQUAL "DirectVulkan")
set(MGL_ITEST_NAMED_BLIT_LABELS "integration-magma-split")
set(MGL_ITEST_NAMED_BLIT_LABELS "${mglItestMagmaLabels}")
else()
set(MGL_ITEST_NAMED_BLIT_LABELS "integration-split")
endif()
foreach(namedBlitCase NamedBlitPreservesBindingsAndRestoresNextVerbsPixels NamedBlitDefaultEndpointPixels)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${namedBlitBackend}.Split.NamedBlit."
TEST_PREFIX "${namedBlitBackend}.${mglItestArm}.NamedBlit."
TEST_FILTER "F1WireScenario.${namedBlitCase}"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "${MGL_ITEST_NAMED_BLIT_LABELS}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_NAMED_BLIT_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5b-${namedBlitBackend}-${namedBlitCase}.log")
${mglItestArmProperties}
ENVIRONMENT "${MGL_ITEST_NAMED_BLIT_ENVIRONMENT}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5b-${namedBlitBackend}${mglItestArmLogTag}-${namedBlitCase}.log")
endforeach()
endforeach()
endforeach()
endif()
@@ -2764,25 +2981,90 @@ endif()
# P5f exit: observe every one of three real drawing frames on both backend roles.
if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(backend DirectGLES DirectVulkan)
# P7 package L: the Magma half on all three transports. `integration-p5f-rsp` itself
# stays on the INPROC entries alone - the CI step that reads it require_greens exactly
# the two names it has always had, and `ctest -L` would have matched a suffixed spelling.
set(p5f_rsp_arms Split)
if (NOT backend STREQUAL "DirectGLES")
set(p5f_rsp_arms ${MGL_ITEST_MAGMA_ARMS})
endif()
foreach(mglItestArm IN LISTS p5f_rsp_arms)
mgl_itest_magma_arm_shape(${mglItestArm} p5f-rsp)
if (backend STREQUAL "DirectGLES")
set(p5f_rsp_label "integration-split")
set(p5f_rsp_label "integration-split\\;integration-p5f-rsp")
elseif (mglItestArm STREQUAL "Split")
set(p5f_rsp_label "integration-magma-split\\;integration-p5f-rsp")
else()
set(p5f_rsp_label "integration-magma-split")
set(p5f_rsp_label "${mglItestMagmaLabels}")
endif()
mgl_itest_join_environment(p5f_rsp_environment
"MOBILEGL_BACKEND_TYPE=${backend}" "MOBILEGL_TRANSPORT=inproc"
"MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" "MGITEST_SPLIT_LANE=1"
"MOBILEGL_BACKEND_TYPE=${backend}" "MGITEST_SPLIT_LANE=1"
"MGITEST_P5F_RSP_LANE=1" "MOBILEGL_PIPE_STATS=1" "MOBILEGL_PIPE_STATS_PERIOD=1"
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-rsp-${backend}.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV})
"MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p5f-rsp-${backend}${mglItestArmLogTag}.log"
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV} ${mglItestArmTransportEnv})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "${backend}.Split.P5fRsp."
TEST_PREFIX "${backend}.${mglItestArm}.P5fRsp."
TEST_FILTER "F1WireScenario.EachWireFrameHasZeroResidualPulls"
DISCOVERY_TIMEOUT 30
PROPERTIES LABELS "${p5f_rsp_label}\;integration-p5f-rsp"
PROPERTIES LABELS "${p5f_rsp_label}"
TIMEOUT ${MGL_ITEST_TIMEOUT}
RESOURCE_LOCK "p5f-rsp-${backend}.log"
RESOURCE_LOCK "p5f-rsp-${backend}${mglItestArmLogTag}.log"
${mglItestArmProperties}
ENVIRONMENT "${p5f_rsp_environment}")
endforeach()
endforeach()
endif()
# =====================================================================================
# P7 PACKAGE L: THE INFORMATIONAL MAGMA CENSUS - TIER 2 OF TWO
# =====================================================================================
#
# THE TWO TIERS, STATED ONCE AND IN ONE PLACE.
#
# TIER 1 - GATED. `integration-magma-split` (inproc, and its meaning is unchanged: the same
# 73 entries, names, labels and private log paths P6.5 left green), plus the two arms this
# package adds beside it, `integration-magma-spawn` and `integration-magma-tcp`. They run the
# SIX HAND-LAID MAGMA LANES - Fm, Buffers, RunAhead, Caches, NamedBlit, P5fRsp - because each
# carries a flavour (strict + dual-block state, adopt tier, run-ahead credits, cache pinning)
# that a shared scenario filter cannot express. A label here may enter a CI gating step only
# after it has been measured green.
#
# TIER 2 - INFORMATIONAL, THIS BLOCK. Every scenario the DirectGLES split arms run, on
# DirectVulkan, on all three transports: `integration-magma-all-split` / `-spawn` / `-tcp`.
# It is in NO CI gating step and must not be added to one wholesale. Its first run's RED LIST
# IS THE P7 WORK LIST - the cases wave 2's clusters A (UniformManager alignment), B
# (blit/copy/mip) and C (vertex / death ops / resident subdata / reflection) divide between
# them - and a red list you cannot record without breaking the build's green is a red list
# nobody writes down. As a cluster retires its share, its cases move UP into tier 1 with the
# commit that retires them, and the gate is honest at every step in between.
#
# WHY IT REPLAYS A RECORDED LIST INSTEAD OF NAMING SCENARIOS. The same argument the spawn arm
# won in P6 (`t6`), one dimension over: a hand-written second list agrees with the first today
# and drifts the first time somebody adds a scenario to one of them, and a Magma census covering
# LESS than the Espryt lane looks exactly like a Magma census covering all of it. The
# registration macro records every call it is given; this replays them, so a scenario added to
# the split arms tomorrow joins the Magma census the same day.
#
# THE THREE ARMS INCLUDE INPROC, and that is the block's diagnostic half: a case red on spawn
# and tcp but GREEN on inproc is a two-process defect (plumbing, a death notice, a reply that
# never crossed), while a case red on all three is Magma's own missing verb and belongs to a
# wave 2 cluster. Without the inproc arm every red would need a hand re-run to tell those apart.
if (MOBILEGL_BUILD_DISAGGREGATED)
list(LENGTH MGL_SPLIT_ARM_CALLS mglItestSplitArmCallCount)
message(STATUS "Integration tests: P7 package L replays ${mglItestSplitArmCallCount} split-arm "
"registration(s) on DirectVulkan under the informational "
"integration-magma-all-{split,spawn,tcp} labels")
foreach(mglItestCall IN LISTS MGL_SPLIT_ARM_CALLS)
# The recorded form is "<filter>|<tail>", with "-" standing for an empty tail. Split by
# regex rather than by list(GET): a filter is allowed to contain anything but `|`, and a
# CMake list cannot represent a trailing empty element unambiguously.
string(REGEX REPLACE "\\|[^|]*$" "" mglItestReplayFilter "${mglItestCall}")
string(REGEX REPLACE "^.*\\|" "" mglItestReplayTail "${mglItestCall}")
if(mglItestReplayTail STREQUAL "-")
set(mglItestReplayTail "")
endif()
mgl_itest_register_split_arms_for_backend(DirectVulkan "${mglItestReplayFilter}"
"${mglItestReplayTail}")
endforeach()
endif()
@@ -48,8 +48,15 @@ def paths(document):
props = {p["name"]: p["value"] for p in test.get("properties", [])}
values = [v.split("=", 1)[1] for v in props.get("ENVIRONMENT", [])
if v.startswith("MOBILEGL_LOG_FILE_PATH=")]
# P7 package L: the Magma arms are here for the reason the GLES ones are - on a spawn or
# tcp arm TWO PROCESSES append to the path, so two entries sharing one file does not
# merely blur attribution, it interleaves two sessions. Leaving the DirectVulkan spawn
# and tcp prefixes out would have exempted the half of the new lane that needs the rule
# most, and the exemption would have looked like a clean run of this gate.
is_split = test["name"].startswith(("DirectGLES.Split.", "DirectVulkan.Split.",
"DirectGLES.Spawn.", "DirectGLES.Tcp.", "DirectGLES.TcpDevice."))
"DirectGLES.Spawn.", "DirectGLES.Tcp.",
"DirectGLES.TcpDevice.",
"DirectVulkan.Spawn.", "DirectVulkan.Tcp."))
if is_split and (len(values) != 1 or not values[0]):
raise ValueError(f"{test['name']}: requires exactly one nonempty MOBILEGL_LOG_FILE_PATH")
for value in values:
+89
View File
@@ -16,6 +16,14 @@ PUSH-MONOLITH arm (the CMakeLists explains why: the label means "the set the dis
runs", not "runs inproc"), and that arm's scenario is monolith-only by construction. It cannot
have a spawn counterpart, so it is named as an exception rather than allowed to widen the
tolerance for everything else.
P7 PACKAGE L ADDS THE SAME QUESTION FOR MAGMA, IN TWO TIERS, AND THE NORMALISATION IS
DIFFERENT ON PURPOSE. The Espryt half above strips the sub-lane tails `F1.` and `Ct.` because
they name neither the case nor the arm. The Magma half must NOT: `RunAhead.Credit1.` and
`RunAhead.Credit3.` are two entries of the same case, differing in the credit the lane pins, and
a normaliser that dropped the tail would fold them together and then report an equal-sized set
that had silently lost one. So there the arm - and only the arm, the SECOND dotted segment - is
what comes off.
"""
import argparse
import re
@@ -27,6 +35,39 @@ MONOLITH_ONLY = {"MonolithAttachmentClearScenario"}
CASE = re.compile(r"DirectGLES\.[A-Za-z0-9]+\.(?:F1\.|Ct\.)?([A-Za-z0-9_]+Scenario\.[A-Za-z0-9_]+)")
# `<Backend>.<Arm>.<everything else>` -> `<Backend>.<everything else>`. The arm is the only
# segment two arms of one lane are allowed to differ in.
ARM = re.compile(r"^(DirectGLES|DirectVulkan)\.(Split|Spawn|Tcp|TcpDevice)\.(.+)$")
TEST_LINE = re.compile(r"^\s*Test\s+#\d+:\s*(\S+)\s*$", re.MULTILINE)
# `ctest -N -L <tcp label>` lists the FIXTURE entries too, because every tcp entry declares
# FIXTURES_REQUIRED mobilegl-tcp and ctest pulls the setup/cleanup in with them. They are the
# supervisor, not cases, and they exist on exactly one arm by construction. Named here so that
# any OTHER unparseable name is still an error rather than a silent drop.
FIXTURE_ENTRIES = {"TcpServer.Start", "TcpServer.Stop"}
# THE MAGMA TIER'S SANCTIONED ASYMMETRIES, LISTED HERE AND NOWHERE ELSE - the same discipline
# MONOLITH_ONLY above gets. Both are inproc-only BY CONSTRUCTION, not by omission:
# MagmaRunAheadScenario arms its hold through ServerLoopInstance().SetBeforeRetireHookForTesting,
# a hook on the CALLING process's server loop. With the server in another
# process the hold never activates and the wait times out.
# MagmaWireCacheScenario SetUp asserts runtime.transportName == "inproc" outright: the lane reads
# the server's own view/attachment identity out of this process.
# A cross-process hold and a cross-process cache peek are server-side knobs neither exists yet;
# until they do, naming the two scenarios here keeps the tolerance from widening for anything else.
MAGMA_INPROC_ONLY = ("MagmaRunAheadScenario.", "MagmaWireCacheScenario.")
def lane_names(build_dir, label):
"""Every ctest entry name under an ANCHORED label (`ctest -L` is a regex, not a name)."""
out = subprocess.run(["ctest", "-N", "-L", "^" + label + "$"], cwd=build_dir,
capture_output=True, text=True, check=True).stdout
return {m.group(1) for m in TEST_LINE.finditer(out)}
def arm_keys(names):
return {f"{m.group(1)}.{m.group(3)}" for m in (ARM.match(n) for n in names) if m}
def lane_cases(build_dir, label):
out = subprocess.run(["ctest", "-N", "-L", "^" + label + "$"], cwd=build_dir,
@@ -34,6 +75,44 @@ def lane_cases(build_dir, label):
return {m.group(1) for m in CASE.finditer(out)}
def compare_arms(build_dir, tier, labels):
"""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."""
sets = {}
for arm, label in labels.items():
names = lane_names(build_dir, label) - FIXTURE_ENTRIES
sets[arm] = arm_keys(names)
print(f"{tier}: {label} has {len(names)} case entrie(s), "
f"{len(sets[arm])} after normalisation")
if len(names) != len(sets[arm]):
print(f"::error::{label}: {len(names) - len(sets[arm])} entry name(s) do not parse "
f"as <Backend>.<Arm>.<case>, so this comparison silently drops them: "
+ ", ".join(sorted(n for n in names if not ARM.match(n))), file=sys.stderr)
return True
if not any(sets.values()):
print(f"::note::{tier}: no entries under {sorted(labels.values())} - nothing to compare")
return False
failed = False
reference = "split"
comparable = {k for k in sets[reference]
if not any(only in k for only in MAGMA_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)})")
for arm, keys in sets.items():
if arm == reference:
continue
missing, extra = sorted(comparable - keys), sorted(keys - comparable)
if missing or extra:
print(f"::error::{tier}: the {arm} arm does not match the {reference} arm: "
f"missing={missing}, extra={extra}. Every arm of a tier is emitted from one "
f"loop over the same case list, so a difference here is a registration bug, "
f"not a coverage decision.", file=sys.stderr)
failed = True
return failed
def main():
parser = argparse.ArgumentParser()
parser.add_argument("build_dir")
@@ -76,6 +155,16 @@ def main():
if not cases or missing or extra:
print(f"::error::{label}: missing={missing}, extra={extra}", file=sys.stderr)
failed = True
# P7 package L, exit gate 1's half of the same question: the Magma arms.
failed |= compare_arms(args.build_dir, "magma gated tier",
{"split": "integration-magma-split",
"spawn": "integration-magma-spawn",
"tcp": "integration-magma-tcp"})
failed |= compare_arms(args.build_dir, "magma informational tier",
{"split": "integration-magma-all-split",
"spawn": "integration-magma-all-spawn",
"tcp": "integration-magma-all-tcp"})
return 1 if failed else 0