diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0bc7febd..05a57124 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -852,6 +852,206 @@ jobs: path: /tmp/core.* if-no-files-found: ignore + # P7 WAVE 3 (V1), CONTRACT-P7 §6 - EXIT GATE 2's SECOND COLUMN: the comparator on the split + # (inproc) arm, both backends, and the two negative controls red on that arm. + # + # ITS OWN BUILD, because neither existing one can carry it: build-linux-verify configures + # without MOBILEGL_BUILD_DISAGGREGATED (so MG_Remote and the transport parser do not exist and + # `MOBILEGL_TRANSPORT=inproc` would be accepted and ignored), and build-linux-split configures + # without MOBILEGL_PIPE_VERIFY (so the comparator does not exist). The integration-verify-split + # entries are registered only when BOTH options are on, so `--no-tests=error` below reds a build + # that lost either one instead of reporting a green run of nothing. Built and run in one job: + # nothing downstream consumes this library. + # + # INPROC ONLY, BY THE INSTRUMENT'S NATURE: the comparator's two arms (the applier-written + # gPipeInputs and the frontend GLContext) are co-resident only when both roles share a process. + # MG_IntegrationTest/CMakeLists.txt's verify-split block records the spawn measurement. + integration-verify-split: + runs-on: ubuntu-latest + timeout-minutes: 180 + permissions: + actions: write + contents: read + env: + BUILD_DIR: build-verify-split + CCACHE_BASEDIR: ${{ github.workspace }} + CCACHE_COMPRESS: "true" + CCACHE_DIR: ${{ github.workspace }}/.ccache + CCACHE_MAXSIZE: 4G + CCACHE_NOHASHDIR: "true" + + steps: + - name: Set Swap Space + uses: pierotofy/set-swap-space@v1.0 + with: + swap-size-gb: 32 + + - name: Checkout repo + uses: actions/checkout@v6 + with: + # recursive for build-linux-split's reason: MOBILEGL_BUILD_DISAGGREGATED shadows itself + # back to OFF when 3rdparty/flatbuffers/include is missing. + submodules: recursive + + - name: Get CMake + uses: lukka/get-cmake@v4.3.3 + + - name: Restore ccache + uses: actions/cache/restore@v5 + with: + path: .ccache + key: ${{ runner.os }}-test-${{ github.job }}-ccache-v1 + restore-keys: | + ${{ runner.os }}-test-${{ github.job }}-ccache- + + - name: Prepare Vulkan SDK + uses: humbletim/setup-vulkan-sdk@v1.2.1 + with: + vulkan-query-version: 1.4.304.1 + vulkan-components: Vulkan-Headers, Vulkan-Loader + vulkan-use-cache: true + + - name: Update glslang external sources + working-directory: 3rdparty/glslang + run: python update_glslang_sources.py + + - name: Install build and runtime dependencies + run: | + sudo apt-get update + sudo apt-get install -y ccache clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev libvulkan-dev libegl1-mesa-dev libgles2-mesa-dev libgl1-mesa-dri mesa-vulkan-drivers ninja-build libvulkan1 libegl1 libegl-mesa0 libgles2 libgl1 + + - name: Configure CMake + # Release/INFO for build-linux-verify's reason, and INFO is load-bearing here for + # build-linux-split's: ConfigLoader's resolved-transport line is logged at INFO and the + # arm-proof step below reads it back out of every entry's client log. + run: | + cmake -S . -B "${BUILD_DIR}" -G Ninja \ + -DCMAKE_C_COMPILER=clang-20 \ + -DCMAKE_CXX_COMPILER=clang++-20 \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_BUILD_TYPE=Release \ + -DMOBILEGL_LOG_ACTIVE_LEVEL=MOBILEGL_LOG_LEVEL_INFO \ + -DMOBILEGL_BUILD_TEST=ON \ + -DMOBILEGL_BUILD_BENCHMARK=OFF \ + -DMOBILEGL_BUILD_INTEGRATION_TEST=ON \ + -DMOBILEGL_ITEST_VK_ICD=/usr/share/vulkan/icd.d/lvp_icd.json \ + -DMOBILEGL_BUILD_TRACE_REPLAY=OFF \ + -DMOBILEGL_PIPE_PUSH=ON \ + -DMOBILEGL_BUILD_DISAGGREGATED=ON \ + -DMOBILEGL_BUILD_DISAGGREGATED_INPROC=ON \ + -DMOBILEGL_PIPE_VERIFY=ON \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + + - name: Build + run: cmake --build "${BUILD_DIR}" --parallel "$(nproc)" + + # Both options, both directions of "did it take" - the two jobs this one is the product of + # each check one of them, and this library has to pass both checks. + - name: The library carries both the comparator and MG_Remote + run: | + test -f "${BUILD_DIR}/libMobileGL.so" + defined=$(nm --defined-only "${BUILD_DIR}/libMobileGL.so" | wc -l) + if [ "${defined}" -lt 1000 ]; then + echo "::error::nm --defined-only sees only ${defined} symbols in ${BUILD_DIR}/libMobileGL.so - it looks stripped, so the checks below could not have failed honestly" + exit 1 + fi + if ! nm --defined-only "${BUILD_DIR}/libMobileGL.so" | grep -q "MGPipeVerifyInputs"; then + echo "::error::libMobileGL.so defines no MGPipeVerifyInputs: -DMOBILEGL_PIPE_VERIFY=ON did not take, and the verify-split lane would compare nothing" + exit 1 + fi + remote=$(nm --defined-only "${BUILD_DIR}/libMobileGL.so" | grep -c -i "MG_Remote" || true) + if [ "${remote}" -lt 1 ]; then + echo "::error::libMobileGL.so defines no MG_Remote symbol: -DMOBILEGL_BUILD_DISAGGREGATED=ON did not take, and every entry would run monolith under a name that says split" + exit 1 + fi + echo "libMobileGL.so defines MGPipeVerifyInputs and ${remote} MG_Remote symbol(s) (${defined} defined symbols)" + + - name: Show ccache stats + if: always() + run: ccache --show-stats + + - name: Release superseded ccache entry + if: github.ref_name == github.event.repository.default_branch + env: + GH_TOKEN: ${{ github.token }} + CACHE_KEY: ${{ runner.os }}-test-${{ github.job }}-ccache-v1 + run: gh cache delete "${CACHE_KEY}" || true + + - name: Save ccache + if: github.ref_name == github.event.repository.default_branch + continue-on-error: true + uses: actions/cache/save@v5 + with: + path: .ccache + key: ${{ runner.os }}-test-${{ github.job }}-ccache-v1 + + # The lane. `^...$` because ctest -L is a regex (ID-131) and `integration-verify` would + # otherwise also match this label and the monolith one would match both. + - name: Integration scenarios under MOBILEGL_PIPE_VERIFY on the split (inproc) arm + working-directory: build-verify-split + env: + MOBILEGL_ITEST_REQUIRE_GPU: "1" + run: | + ulimit -c unlimited + sudo sysctl -w kernel.core_pattern='/tmp/core.%e.%p' + ctest --output-on-failure -L '^integration-verify-split$' --no-tests=error -j 4 + + # THE ARM PROOF, per entry. Every ambient entry has a private log path (SplitLogPaths.cmake.in), + # so this grep - unlike integration-verify's, over a shared log - is a census: + # * ConfigLoader's `MOBILEGL_TRANSPORT=inproc` line in EVERY client log: an entry that ran + # monolith would have passed every assertion above and fails here by name; + # * `MGPipe: verify armed` in both VerifySplitArming. logs, and in at least 850 per-entry + # client logs. The line is latched at a process's first fill, so the processes that never + # reach a verb (limits queries, CapsMirror answers, the poison parent) honestly lack it - + # 909 of 1064 carried it on the landing run - and a count that falls through the floor + # means the comparator stopped arming somewhere after bring-up. + - name: The verify-split entries ran inproc and armed the comparator + working-directory: build-verify-split/MobileGL/MG_IntegrationTest + run: | + shopt -s nullglob + logs=(verify-split-logs/*.client.log) + if [ ${#logs[@]} -lt 1000 ]; then + echo "::error::found ${#logs[@]} per-entry client logs under verify-split-logs (expected ~1064): the private log paths did not take, so nothing below is a per-entry proof" + exit 1 + fi + missing=$(grep -L 'Config: MOBILEGL_TRANSPORT=inproc' "${logs[@]}" | wc -l) + if [ "${missing}" -ne 0 ]; then + grep -L 'Config: MOBILEGL_TRANSPORT=inproc' "${logs[@]}" | head -20 + echo "::error::${missing} verify-split entries carry no resolved MOBILEGL_TRANSPORT=inproc line: they did not run on the split arm" + exit 1 + fi + for backend in DirectGLES DirectVulkan; do + if ! grep -q "MGPipe: verify armed" "pipe-verify-split-arming-${backend}.client.log"; then + echo "::error::pipe-verify-split-arming-${backend}.client.log carries no arming line" + exit 1 + fi + done + armed=$(grep -l 'MGPipe: verify armed' "${logs[@]}" | wc -l) + if [ "${armed}" -lt 850 ]; then + echo "::error::only ${armed} of ${#logs[@]} verify-split entries armed the comparator (floor 850, 909 at landing)" + exit 1 + fi + echo "${#logs[@]} entries resolved inproc; ${armed} of them armed the comparator" + + - name: Upload verify-split lane logs + if: always() + uses: actions/upload-artifact@v7 + with: + name: integration-verify-split-logs + path: | + build-verify-split/MobileGL/MG_IntegrationTest/verify-split-logs/** + build-verify-split/MobileGL/MG_IntegrationTest/pipe-*split*.log* + if-no-files-found: warn + + - name: Upload core dumps + if: failure() + uses: actions/upload-artifact@v7 + with: + name: integration-verify-split-core-dumps + path: /tmp/core.* + if-no-files-found: ignore + # P5's split build. The verify pair cloned, because the problem is the same one: a third # configuration of the same sources whose whole value depends on the option having taken. # diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 58a8df71..40bbaa2d 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -645,6 +645,56 @@ namespace MobileGL::MG_Pipe { MGPipeInputField differing = MGPipeInputField::kFieldCount; if (!MGPipeVerifyInputs(inputs, g_snapshot, mask, &differing)) ReportDivergence(differing, "entry"); } + +#if MOBILEGL_BUILD_DISAGGREGATED + // ---- P7 wave 3 (V1): the compare-at-read oracle inside the server's read_pixels ---- + // + // WHAT THE SPLIT ARM FOUND THE FIRST TIME VERIFY AND SPLIT SHARED A BUILD. Every + // glReadPixels on the inproc arm - 8530 reads over 220 of the lane's 1068 entries, and the + // VerifySplitArming. entries on both backends - aborted with + // + // MGPipe: verify read of GetPixelStoreParameters (index 0, 0) differs from the live context + // MGPipe: Fatal{PipeVerifyDiffer, "GetPixelStoreParameters@ReadPixels", verb=6, where=read} + // + // on the server's apply thread, and it was the ONLY field that diverged anywhere in the + // lane. The mechanism is ID-49 and is deliberate: the pack state never shapes the wire + // answer, so MG_Remote/Server/PipeApplier.cpp's read_pixels body writes a NEUTRAL pack + // into the applier's copy of the field (MGPipeApplySetPixelPackState), makes the backend + // read, and restores the pushed one; the client then scatters the tight reply through the + // application's own pack state. The frontend context - this comparator's oracle - still + // holds the application's pack (Alignment 4 by default), so the backend's read of the + // pack half answers {Alignment 1} where the live context says {Alignment 4}. On the + // monolith arm the same neutral window is opened on the frontend context itself + // (GL_Texture.cpp's ScopedNeutralPackState), which is why the monolith lane never saw it. + // + // SO THE ORACLE, NOT THE RULE, IS WHAT CHANGES, AND ONLY IN THAT WINDOW: under a server + // stamp, on the ReadPixels verb, the pack half's expected value is the neutral pack the + // applier reads with, and the UNPACK half and every other field keep the live context as + // their oracle. A server read of the pack half that is neither the application's value + // nor exactly the neutral one is still a divergence and still Fatal. What this gives up, + // stated: on the server's ReadPixels the comparator can no longer see a client that + // pushed a WRONG pack state, because the applier overwrites it before the backend reads; + // the client-side scatter that consumes the real pack is covered by the readback matrix + // cases, which compare bytes, not fields. + Bool ServerReadsInsideTheNeutralPackWindow(const PipeInputs& self, MGPipeInputField field) { + return field == MGPipeInputField::GetPixelStoreParameters && self.ServerStampedVerb() && + self.CurrentVerb() == MGPipeVerb::ReadPixels; + } + + // PipeApplier.cpp's `neutralPack`, field for field. A second spelling of a constant is + // the price of not reaching into MG_Remote/Server from here; if the two ever part, the + // server-side read stops matching this and the lane goes red by name, which is the + // direction that fails loudly. + PixelStoreParameters ServerReadPixelsNeutralPack() { + PixelStoreParameters neutral{}; + neutral.RowLength = 0; + neutral.SkipRows = 0; + neutral.SkipPixels = 0; + neutral.SkipImages = 0; + neutral.Alignment = 1; + return neutral; + } +#endif // MOBILEGL_BUILD_DISAGGREGATED #endif // MOBILEGL_PIPE_VERIFY } // namespace @@ -682,6 +732,23 @@ namespace MobileGL::MG_Pipe { const Bool equal = MGPipeInputsFieldEqual(field, self, g_readScratch); g_verify.InHook = false; if (equal) return; +#if MOBILEGL_BUILD_DISAGGREGATED + if (ServerReadsInsideTheNeutralPackWindow(self, field)) { + // The live context is the application's pack state and the server is, by ID-49, + // reading with the neutral one; the oracle for THAT HALF is the neutral pack, and + // every other byte of the field still has to match the live context. + g_verify.InHook = true; + PipeInputs::VisitStorage(field, g_readScratch, g_readScratch, [](auto& live, auto&) { + if constexpr (std::is_same_v, PixelStoreParameters[2]>) { + live[0] = ServerReadPixelsNeutralPack(); + } + return true; + }); + const Bool equalToTheNeutralPack = MGPipeInputsFieldEqual(field, self, g_readScratch); + g_verify.InHook = false; + if (equalToTheNeutralPack) return; + } +#endif MGLOG_E("MGPipe: verify read of %s (index %u, %u) differs from the live context", kMGPipeInputFieldNames[index], index0, index1); ReportDivergence(field, "read"); diff --git a/MobileGL/MG_IntegrationTest/CMakeLists.txt b/MobileGL/MG_IntegrationTest/CMakeLists.txt index a5a57251..af4a35ab 100644 --- a/MobileGL/MG_IntegrationTest/CMakeLists.txt +++ b/MobileGL/MG_IntegrationTest/CMakeLists.txt @@ -3778,6 +3778,167 @@ if (MOBILEGL_BUILD_DISAGGREGATED) "integration-magma-full-{split,spawn,tcp} labels (no CI gate)") endif() +# ===================================================================================== +# P7 WAVE 3 (V1): integration-verify-split - THE COMPARATOR ON THE SPLIT ARM +# ===================================================================================== +# +# CONTRACT-P7 §6, exit gate 2: "verify x {monolith, split(inproc)} x Magma, zero divergence". +# Until this block the verify block near the top of this file registered `MOBILEGL_TRANSPORT= +# monolith` on every one of its 1136 entries, so the gate's second column had no entries at all +# - not merely unmet, UNMEASURABLE, exactly as package L found exit gate 1's Magma column. +# +# IT HAD A PREREQUISITE AND THE PREREQUISITE IS PAID. A verify build under `inproc` used to die +# on the server apply thread before one case could arm: +# +# Fatal{PipeRespecifyScope} resource_respecify {slot=12, gen=0}: the descriptor carries a +# per-level respecify scope (target=258, level=0), and no path in this phase may set one +# +# That pin is now "a per-level producer must cover the range it declares" +# (MG_Pipe/PipeApply.cpp), which is the invariant it was actually guarding. +# +# BOTH BACKENDS, AND THE MAGMA HALF IS THE HALF THE GATE NAMES. `${MGL_ITEST_VULKAN_ENV}` and +# not `${MGL_ITEST_COMMON_ENV}` on the DirectVulkan entries, for package L's reason: that list +# carries VK_ICD_FILENAMES and the three lavapipe iterationRP repairs the monolith `DirectVulkan.` +# arm has been pinned to, and a lane that appended the common list would measure a different +# driver from the gate it is compared against. `MOBILEGL_ITEST_REQUIRE_GPU=1` is pinned for the +# same reason every split-family lane pins it: a lane that skipped everything and a lane that +# passed everything are the same green in ctest, and this lane is here to be an ARM. +# +# THE CASE SET IS THE MONOLITH VERIFY LANE'S, MINUS THREE THINGS, the first two because +# this arm carries a TRANSPORT and that lane does not: +# +# 1. ${MGL_ITEST_MONOLITH_MECHANISM_FILTER}. Those oracles toggle process-local push masks, +# pointer-key ABA, direct persistent adoption or synchronous stats slots and must not +# inherit a transport - which is why the ambient DirectGLES./DirectVulkan. registrations +# subtract them too and re-register them with MOBILEGL_TRANSPORT=monolith pinned. The +# monolith verify lane keeps them because there the pin and the lane agree. NOTE that the +# filter names PipeVerifyArmingScenario.* and PoisonOmissionScenario.*, which is why the +# arming entry and the two negative controls below are registered by hand, one per backend, +# exactly as the monolith verify block registers its own. +# 2. DualBlockScenario.*. Its green REQUIRES MOBILEGL_IPC_ROLE_SPLIT_STATE=1, and pinning that +# knob here would replace this lane's subject (the comparator) with a different experiment; +# without it the case is red by name. Tier 3 above filters it for the same reason and says +# so at more length. Its own lane, `integration-dualblock-split`, is where it is read. +# 3. On the DirectGLES half only, four Magma wire-arm decline cases that are red on DirectGLES +# x inproc with the comparator OFF (MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER below +# says which and why). +# +# NO MGITEST_SPLIT_LANE=1, AND THIS IS THE ONE PLACE THAT COSTS SOMETHING, so it is stated +# rather than discovered. That marker arms ScenarioFixture's destructor assertion "this case +# must have MOVED the client encoder's record ordinal", which is right for a curated lane where +# every entry draws and wrong for a whole-binary set: tier 3 measured 13 reds from it +# (AdvertisedLimitsScenario x8, SpirvShaderBinaryScenario x4, ProgramPipelineScenario's reserved +# name), every one of them a query answered from the client's CapsMirror without a verb. They +# would red on a DirectGLES set too - a property of the census, not of the transport. +# +# WHAT REPLACES IT IS STRONGER HERE THAN IT IS IN TIER 3, and it is why this lane is armed +# rather than green-skipping: EVERY ENTRY GETS A PRIVATE LOG PATH (below, through +# MGL_VERIFY_SPLIT_TEST_LISTS), and `.github/workflows/test.yml`'s integration-verify-split job +# reads all of them: ConfigLoader's resolved `MOBILEGL_TRANSPORT=inproc` line is required in EVERY +# client log, so a lane that silently ran monolith fails that step by name. The comparator's +# `MGPipe: verify armed` line is latched at a process's FIRST FILL, so it is absent - honestly - +# from the processes that never reach a verb (limits queries, CapsMirror answers, the poison +# parent that only forks; 155 of 1064 on the landing run, 99 of them skips); the step therefore +# requires it in both VerifySplitArming. logs and holds the per-entry count to a stated floor. +# The VerifySplitArming. entries assert it from inside the process as well, which is the shape +# the monolith lane's VerifyArming. entries already have. +if (MOBILEGL_BUILD_DISAGGREGATED AND MOBILEGL_PIPE_VERIFY) + # The transport half, joined onto each backend's own list. One place says what "the verify + # split arm" means, as MGL_ITEST_SPLIT_ARM_TRANSPORT_ENV does for the Magma lanes. + set(MGL_ITEST_VERIFY_SPLIT_ARM_ENV + "MOBILEGL_TRANSPORT=inproc" "MOBILEGL_IPC_SERVER_PATH=${MGL_ITEST_SPLIT_SERVER_PATH}" + "MOBILEGL_PIPE_VERIFY=1" "MOBILEGL_ITEST_REQUIRE_GPU=1") + mgl_itest_join_environment(MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT + "MOBILEGL_BACKEND_TYPE=DirectGLES" ${MGL_ITEST_VERIFY_SPLIT_ARM_ENV} + ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_COMMON_ENV}) + mgl_itest_join_environment(MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT + "MOBILEGL_BACKEND_TYPE=DirectVulkan" ${MGL_ITEST_VERIFY_SPLIT_ARM_ENV} + ${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV}) + + # THE FOUR MAGMA DECLINE CASES ARE SUBTRACTED FROM THE DirectGLES HALF ONLY, and not because + # of the comparator. They assert Magma's wire-arm decline contract (`@P7` retirements: the + # depth-stencil mip decline, the two multisample blit declines, the overlapping in-place copy) + # and skip on every monolith arm, so the only arm that registers them is DirectVulkan's + # split family. On DirectGLES x inproc they are RED WITH THE COMPARATOR OFF - measured on + # this build with MOBILEGL_PIPE_VERIFY=0 in the same environment, the same four assertions + # (GL error 0x0502 where the decline promises none, or none where it promises one; the + # overlap copy writes the level the decline leaves alone) - because Espryt does not decline + # those shapes at all. No DirectGLES split lane had ever run them; that is a finding about the + # DirectGLES whole-binary set on split, not about verify, and it is recorded in + # notes/p7/verify-split.md rather than hidden in a green. The DirectVulkan half keeps them. + set(MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER + "F1WireScenario.GenerateMipmapDepthStencilDeclinesAndKeepsTheSession:F1WireScenario.MultisampleBlitOntoAMultisampleDestinationDeclinesAndKeepsTheSession:F1WireScenario.MultisampleBlitFromASingleSampleSourceDeclinesAndKeepsTheSession:F1WireScenario.CopyImageInPlaceOverlapDeclinesAndLeavesTheLevelAlone") + + set(MGL_VERIFY_SPLIT_TEST_LISTS "") + # The ambient set, per backend. The GLES half is registered TWICE for the monolith verify + # lane's reason and with its spelling: the texture-view cases need + # MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1 or DirectGLES withholds GL_ARB_texture_view and they + # green-skip, so they are subtracted from the first registration and re-registered with the + # knob. "Every existing verify case on the split arm" is false without the second block. + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectGLES.VerifySplit." + TEST_LIST MGL_VERIFY_SPLIT_TESTS_GLES + TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:${MGL_ITEST_GLES_VIEW_FILTER}:DualBlockScenario.*:${MGL_ITEST_VERIFY_SPLIT_GLES_MAGMA_DECLINE_FILTER}" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-verify-split" + TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT} + ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}" + ) + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectGLES.VerifySplit." + TEST_LIST MGL_VERIFY_SPLIT_TESTS_GLES_VIEW + TEST_FILTER "${MGL_ITEST_GLES_VIEW_FILTER}" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-verify-split" + TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT} + ENVIRONMENT "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}\;MOBILEGL_ESPRYT_ENABLE_TEXTURE_VIEW=1" + ) + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectVulkan.VerifySplit." + TEST_LIST MGL_VERIFY_SPLIT_TESTS_VULKAN + TEST_FILTER "-${MGL_ITEST_MONOLITH_MECHANISM_FILTER}:DualBlockScenario.*" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-verify-split" + TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT} + ENVIRONMENT "${MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT}" + ) + list(APPEND MGL_VERIFY_SPLIT_TEST_LISTS MGL_VERIFY_SPLIT_TESTS_GLES + MGL_VERIFY_SPLIT_TESTS_GLES_VIEW MGL_VERIFY_SPLIT_TESTS_VULKAN) + + # The arming assertion on this arm, one entry per backend, with a log path nothing else + # writes to - the monolith VerifyArming. entries' shape and their reason (the case reads the + # whole file, and a path shared with 500 neighbours races them under `-j 4`). This is the + # entry that cannot be green against a library with no comparator compiled in, and unlike the + # monolith pair it also cannot be green against one whose comparator never survived the + # server's bring-up - which is precisely what the relaxed respecify pin unblocked. + # + # MGITEST_PIPE_ARMING_LANE=1 is a harness marker the library never reads; it is what makes + # the case skip in an ambient lane rather than race there. + foreach(mglItestVerifyBackend DirectGLES DirectVulkan) + if (mglItestVerifyBackend STREQUAL "DirectGLES") + set(mglItestVerifyArmEnv "${MGL_ITEST_GLES_VERIFY_SPLIT_ENVIRONMENT}") + else() + set(mglItestVerifyArmEnv "${MGL_ITEST_VULKAN_VERIFY_SPLIT_ENVIRONMENT}") + endif() + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "${mglItestVerifyBackend}.VerifySplitArming." + TEST_FILTER "PipeVerifyArmingScenario.Armed" + DISCOVERY_TIMEOUT 30 + PROPERTIES + LABELS "integration-verify-split" + TIMEOUT ${MGL_ITEST_VERIFY_TIMEOUT} + ENVIRONMENT "${mglItestVerifyArmEnv}\;MGITEST_PIPE_ARMING_LANE=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/pipe-verify-split-arming-${mglItestVerifyBackend}.log" + RESOURCE_LOCK "pipe-verify-split-arming-${mglItestVerifyBackend}.log" + ) + endforeach() + + message(STATUS "Integration tests: P7 wave 3 - the verify comparator on the split (inproc) arm, " + "both backends, under integration-verify-split") +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 722fbb20..19d53277 100644 --- a/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in +++ b/MobileGL/MG_IntegrationTest/Harness/SplitLogPaths.cmake.in @@ -1,6 +1,7 @@ # Included by CTest after all GoogleTest discovery files (ID-53). # CTest appends ENVIRONMENT here; keep all previously discovered lane settings. file(MAKE_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@/split-logs") +file(MAKE_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@/verify-split-logs") # P5b t2's two lanes ride the same rule: one private log path per entry, or # SplitLogPaths.PrivateAndDistinct is red for them (ID-53). # P5e vi's client-array lane joins the same list for the same reason: its two entries are the @@ -52,6 +53,25 @@ foreach(listName IN ITEMS @MGL_MAGMA_FULL_TEST_LISTS@) endif() endforeach() endforeach() +# P7 wave 3 (V1): the verify comparator on the split arm. A LIST OF ITS OWN, like tier 3's and +# for tier 3's reason - the first loop also arms the strict-arming, pmap and server-counter lane +# markers by entry name, and this lane is here to compare fields, not to opt three unrelated +# oracles into a whole-binary set. +# +# THE PATH IS WHAT MAKES THE LANE ARMED RATHER THAN MERELY GREEN. These entries carry no +# MGITEST_SPLIT_LANE marker (MG_IntegrationTest/CMakeLists.txt says why: it reds 13 query-only +# cases that never move a verb), so the proof that the transport really resolved to inproc and +# that the comparator really armed is READ FROM THESE FILES by test.yml's verify-split job - +# ConfigLoader's `MOBILEGL_TRANSPORT=inproc` line and `MGPipe: verify armed`, per entry, in the +# CLIENT role's log. A shared path would make both unattributable, and under inproc the server +# role writes its own half of the same base name. +foreach(listName IN ITEMS @MGL_VERIFY_SPLIT_TEST_LISTS@) + foreach(entry IN LISTS ${listName}) + set_tests_properties("${entry}" PROPERTIES ENVIRONMENT + "MOBILEGL_LOG_FILE_PATH=@CMAKE_CURRENT_BINARY_DIR@/verify-split-logs/${entry}.log") + 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")