[CI] (.github/workflows, docs/ci, scripts/ci): fold the strict split lane into the dual-block run

- on the disaggregation branches the dual-block census step's first run leaves MOBILEGL_IPC_ROLE_SPLIT_STATE at its default, which makes its environment the strict split lane's; the step proves per entry that strict, the dual block and run-ahead resolved on, and makes the strict lane's checks on that run
- junit_tally.py --select-from/--write-selected carves the integration-split part out of dualblock.xml as strict-split.xml, every name exactly once (exit 3 otherwise); tests in tcp_lane_tools_test.py
- 'Strict split lane' runs on dev only; 'Magma split lane' is skipped when the dual-block run proved its defaults, since that run covers the label in the same environment; a changed default reruns the census with the knob set
This commit is contained in:
2026-10-17 16:08:40 -04:00
parent d5dfc9ffff
commit 5ce4890c10
4 changed files with 145 additions and 8 deletions
+80 -8
View File
@@ -1822,8 +1822,11 @@ jobs:
#
# An unbarriered pull is always fatal, and strict also stops any barriered pull that is not
# admitted (ARCHITECTURE.md §9.2.1). The lane must be green, and its markers must match the
# admitted list and strict-expected-markers.txt in both directions.
# admitted list and strict-expected-markers.txt in both directions. On the disaggregation
# branches the dual-block step below runs these entries in this same environment and makes
# the same checks, so this step runs on dev only.
- name: Strict split lane
if: env.MOBILEGL_CI_DISAGGREGATED != 'ON'
working-directory: ${{ env.SPLIT_BUILD_DIR }}
env:
MOBILEGL_ITEST_REQUIRE_GPU: "1"
@@ -1927,7 +1930,13 @@ jobs:
# is ratcheted two-sided against Harness/dualblock-expected-fatals.txt: a new pair is a
# debt somebody now owes, a vanished pair must be removed in the commit that retired it.
# With the census empty, this lane is a hard green gate.
# On the disaggregation branches the first run is also the strict split lane: the knob is
# left at its default, which every passed entry's own log must show is the dual block, so
# the environment is the strict lane's exactly. Its checks are made on that run (the
# integration-split part of the JUnit becomes strict-split.xml); a default that changed
# reruns the census with the knob set, as on dev.
- name: Dual-block census lane
id: dualblock
working-directory: ${{ env.SPLIT_BUILD_DIR }}
env:
MOBILEGL_ITEST_REQUIRE_GPU: "1"
@@ -1938,11 +1947,13 @@ jobs:
ulimit -c unlimited
helper="${GITHUB_WORKSPACE}/MobileGL/MG_IntegrationTest/Harness/split_log_paths.py"
expected="${GITHUB_WORKSPACE}/MobileGL/MG_IntegrationTest/Harness/dualblock-expected-fatals.txt"
strict_expected="${GITHUB_WORKSPACE}/MobileGL/MG_IntegrationTest/Harness/strict-expected-markers.txt"
ctest -L 'integration-split|integration-magma-split' --show-only=json-v1 \
> "${RUNNER_TEMP}/dualblock-lane.json"
# Stale logs from an earlier step would be read as this run's evidence (ID-119's rule).
reset_logs() {
python3 - "${RUNNER_TEMP}/dualblock-lane.json" "${helper}" <<'PY'
import importlib.util, json, os, sys
spec = importlib.util.spec_from_file_location("slp", sys.argv[2])
@@ -1955,13 +1966,71 @@ jobs:
pass
print(f"reset {len(set(logs.values()))} private log(s) across {len(logs)} entries")
PY
}
census_run() {
rc=0
ctest -L 'integration-split|integration-magma-split' --no-tests=error -j 4 \
--output-junit "${RUNNER_TEMP}/dualblock.xml" \
> "${RUNNER_TEMP}/dualblock-split.txt" 2>&1 || rc=$?
tail -5 "${RUNNER_TEMP}/dualblock-split.txt"
echo "dual-block census run: rc=${rc}"
}
reset_logs
rc=0
ctest -L 'integration-split|integration-magma-split' --no-tests=error -j 4 \
--output-junit "${RUNNER_TEMP}/dualblock.xml" \
> "${RUNNER_TEMP}/dualblock-split.txt" 2>&1 || rc=$?
tail -5 "${RUNNER_TEMP}/dualblock-split.txt"
echo "dual-block census run: rc=${rc}"
if [ "${MOBILEGL_CI_DISAGGREGATED}" != ON ]; then
census_run
else
# Run A: the strict split lane's environment, with the role-split state at its default.
saved_role="${MOBILEGL_IPC_ROLE_SPLIT_STATE}"
unset MOBILEGL_IPC_ROLE_SPLIT_STATE
census_run
export MOBILEGL_IPC_ROLE_SPLIT_STATE="${saved_role}"
# The strict lane's JUnit is the integration-split part of this run, every name once.
ctest -L integration-split --show-only=json-v1 > "${RUNNER_TEMP}/lane.json"
selected=0
python3 "${GITHUB_WORKSPACE}/scripts/ci/junit_tally.py" "${RUNNER_TEMP}/dualblock.xml" \
--select-from "${RUNNER_TEMP}/lane.json" --write-selected "${RUNNER_TEMP}/strict-split.xml" || selected=$?
python3 "${GITHUB_WORKSPACE}/scripts/gen_pipe_field_ownership.py" --print-admitted \
> "${RUNNER_TEMP}/allowed.txt"
echo "allowlist (derived): $(wc -l < "${RUNNER_TEMP}/allowed.txt") admitted pair(s)"
if [ "${rc}" -ne 0 ]; then
echo "::error::the strict run of integration-split and integration-magma-split under MOBILEGL_IPC_STRICT_ERRORS=1 is RED on a run-ahead server. It is a hard green gate; the census below names the field and the verb of every integration-split entry that aborted, and dualblock-split.txt holds both labels' output."
python3 "${helper}" markers "${RUNNER_TEMP}/lane.json" '.' \
"${RUNNER_TEMP}/allowed.txt" "${strict_expected}" || true
exit 1
fi
if [ "${selected}" -ne 0 ]; then
echo "::error::the dual-block run's JUnit does not hold every integration-split entry exactly once, so it cannot stand for the strict split lane"
exit 1
fi
# The strict lane's two-sided marker census and its arming proof, as in its own step.
python3 "${helper}" markers "${RUNNER_TEMP}/lane.json" '.' \
"${RUNNER_TEMP}/allowed.txt" "${strict_expected}" no-fatal
if ! grep -q 'DirectGLES\.Split\.StrictArming\.' "${RUNNER_TEMP}/dualblock-split.txt"; then
echo "::error::the strict run did not run DirectGLES.Split.StrictArming., so nothing in this run proves the server ever stamped a verb boundary. A green lane without it is indistinguishable from a lane where strict was never armed."
exit 1
fi
echo "integration-split under strict is GREEN, two-sided, with the arming control present"
# Run A is the census run when every passed entry resolved the dual block (and strict
# and run-ahead) on its own; a default that changed reruns with the knob set.
ipc=0
python3 "${helper}" ipc-config "${RUNNER_TEMP}/dualblock-lane.json" "${RUNNER_TEMP}/dualblock.xml" \
"${RUNNER_TEMP}/dualblock-ipc.json" strict=1 role-split-state=1 run-ahead=1 \
--assumed role-split-state,run-ahead || ipc=$?
if [ "${ipc}" -eq 0 ]; then
echo "defaults-on=true" >> "${GITHUB_OUTPUT}"
elif [ "${ipc}" -eq 3 ]; then
echo "::warning::the role-split state or run-ahead default is not on (dualblock-ipc.json names the entries), so the census reruns with MOBILEGL_IPC_ROLE_SPLIT_STATE=1"
echo "defaults-on=false" >> "${GITHUB_OUTPUT}"
rm -f "${RUNNER_TEMP}/dualblock.xml"
reset_logs
census_run
else
exit "${ipc}"
fi
fi
rows=$(awk '!/^[[:space:]]*(#|$)/ { n++ } END { print n+0 }' "${expected}")
if [ "${rows}" -eq 0 ] && [ "${rc}" -ne 0 ]; then
@@ -1996,8 +2065,11 @@ jobs:
# ---- MAGMA'S OWN WIRE LANE: FRAMEBUFFER, TEXTURE AND APPLICATION BUFFERS ------------
#
# P5f fm: Magma's framebuffer, copy and mipmap verbs consume server records.
# The label remains separate so both backends' coverage stays explicit.
# The label remains separate so both backends' coverage stays explicit. The dual-block
# census run above covers the label in this same environment; with its defaults proven on
# the disaggregation branches this step would repeat it, so it runs only otherwise.
- name: Magma split lane (strict, dual-block)
if: env.MOBILEGL_CI_DISAGGREGATED != 'ON' || steps.dualblock.outputs.defaults-on != 'true'
working-directory: ${{ env.SPLIT_BUILD_DIR }}
env:
MOBILEGL_ITEST_REQUIRE_GPU: "1"