[MG_Pipe, MG_Impl, MG_IntegrationTest, CI, Docs] (Disaggregated): P5e ra2 - ID-133's escalation, ID-134's lane, and the contract sentence that could not be checked

- ID-133: escalation (iii) in MGPipeBarriered - a draw_vbo with NumDraws > 1 that is NOT
  kDrawIsIndirect is barriered. Espryt's indirect multi-draw tiers reach
  MultiDrawImpl::RunIndirect, whose apply reads the client's GL_DRAW_INDIRECT_BUFFER binding
  (BoundDrawIndirectBufferId, MultiDraw.cpp:87) - GetBufferBindingSlot, retiring in P8 - and
  unbarriered that is Fatal{UnmigratedPipeInput, "GetBufferBindingSlot@DrawArrays"} on 18 lane
  entries. Backtrace of the aborting thread, verbatim frames: CountBarrierPull <-
  MultiDrawImpl::RunIndirect <- MultiDrawImpl::DrawElementsBatch <- ServerVerbSink::OnDrawVbo
  <- PipeWireDecoder::DecodeAndApply <- PipeApplier::ApplyOne.
- TWO PREMISE CORRECTIONS, both measured, both in the report and in the contract. (a) There is
  no indirect multi-draw OP: all twenty draw entry points collapse onto draw_vbo, and the tier
  is resolved on the server per batch (ResolveTierForBatch), so the escalation cannot be keyed
  on the tier and its cost is NOT confined to the opt-in tier lanes - a plain glMultiDraw* now
  waits on the auto -> ext default too. NumDraws > 1 is the narrowest wire fact that contains
  the reaching set; kDrawIsIndirect is excluded so Sodium's indirect draw, which resolves by
  handle and pulls nothing, keeps running ahead. (b) The read is a SAVE/RESTORE of a GL binding
  name around the tier's own scratch buffer, not a data dependency - so it can be retired
  outright by giving BoundDrawIndirectBufferId the handle arm its neighbour
  ResolveBoundIndexBuffer already has, and this escalation withdrawn. That is three lines in
  MultiDraw.cpp, which ID-113 gives to mv, so it is reported rather than edited here.
- The client's half is verb-keyed because the fill decision is asked before the record exists:
  {MultiDrawArrays, MultiDrawElements, MultiDrawElementsBaseVertex} is exactly the set whose
  record can carry NumDraws > 1 without kDrawIsIndirect. The inclusion goes that way round on
  purpose - a record the server calls barriered whose fields the client did not fill would be
  an ADMITTED pull of a stale value, which is worse than the abort.
- ID-134: the two ClientVertexArrayScenario entries get the label integration-clientarrays-split
  and an expected-red CI step that asserts the MARKER, shaped like gl's Magma lane. ID-131 heeded
  by COUNTING, not by assuming: -L integration-split 181 -> 179, -L integration-gpu 1359 -> 1357,
  the new label selects exactly 2. The step branches on whether run-ahead is actually ARMED,
  because kMGPipeP5eRunAheadReady is a BUILD constant: on a head where it is false the refusal is
  unreachable and the entries are legitimately green, so an unconditional demand for red would
  fail for the one reason that is not a defect. The client says which world it is in in its own
  log line; delete the green branch when the flip lands for good.
- CONTRACT-P5E §3.5 amended to the code: "outside a barriered fill" rested on the caller's claim
  about the FUTURE, and a guard whose exemption cannot be false on the class it exists for is not
  a guard - it never fired on any of the 70 red entries. The landed rule is "not while the applier
  is inside, barriered fill or not", with the fill sites taking §2.5's forced wait first, twice
  per filling verb because the block is written either side of the emitters.
- AND §3.2 IS MARKED UNLANDED, which nobody had noticed: "the server's stamp is server-private
  … never into the shared block" describes storage the applier owns, and
  MGPipeServerStampVerbBoundary still writes m_filled / m_currentVerb / m_serverStampedVerb into
  gPipeInputs itself. That gap is what made the race possible. Splitting the stamp is the P11
  item - but per-role stamps WITHOUT versioning the BARRIER_PULLED values would be worse than
  today, because it turns a loud Fatal into a silent stale read.
- §2.1 carries escalation (iii) as a row, per its own rule that a new escalation is a ruling and
  a row in the contract rather than a condition at a call site.
- Gate on the flipped head: unit 2256/2256, isplit 179/179 HARD GREEN, gens rc=0, doc citations
  rc=0 (the three remaining are CONTRACT-P5.md's and pre-date this branch).
This commit is contained in:
2026-09-18 13:56:51 -04:00
parent 2d03565f87
commit f286548010
6 changed files with 201 additions and 3 deletions
+60
View File
@@ -1380,6 +1380,66 @@ jobs:
fi
echo "integration-magma-split is red by design on ${marker}"
# ---- P5e (ra2), ID-134 / ID-82: THE CLIENT-ARRAY LANE, EXPECTED RED UNDER RUN-AHEAD ----
#
# The two DirectGLES.Split.ClientVertexArrayScenario entries draw from a vertex array in
# the application's OWN memory. The server uploads those bytes by dereferencing a raw
# client pointer per draw, which is exactly the read rule F forbids once the client stops
# waiting - so ID-82 makes the draw a NAMED REFUSAL under run-ahead and gives the staging
# form to P8. Aborting is therefore the DESIGNED behaviour, and a lane that demanded these
# entries green would be demanding that the refusal not fire.
#
# THE LABEL, AND WHY IT IS NOT `integration-split-clientarrays` (ID-131): `ctest -L` is a
# REGEX. That spelling is matched by `-L integration-split` as a substring, so the entries
# would still be in the lane they were moved out of while every listing showed them
# renamed. Counted, not assumed: `-L integration-split` went 181 -> 179 and
# `-L integration-gpu` 1359 -> 1357 when this label landed.
#
# IT BRANCHES ON WHETHER RUN-AHEAD IS ACTUALLY ARMED, and that is not hedging - it is the
# only formulation that is a real assertion on BOTH heads. kMGPipeP5eRunAheadReady is a
# BUILD constant (MG_Backend/Init.cpp): on a head where it is false no environment can arm
# run-ahead, the refusal is unreachable, and these entries are green - so a step that
# simply demanded red would fail for the one reason that is not a defect. The client says
# which world it is in, in its own log line, and the step reads that and then demands the
# matching outcome. When the flip lands for good, delete the green branch.
- name: Integration-clientarrays-split - expected red under run-ahead (ID-82 / ID-134)
working-directory: build-split
env:
MOBILEGL_ITEST_REQUIRE_GPU: "1"
MOBILEGL_TRANSPORT: "inproc"
run: |
ulimit -c unlimited
logs=MobileGL/MG_IntegrationTest/split-logs
rm -f "${logs}"/*ClientVertexArrayScenario*.log 2>/dev/null || true
rc=0
ctest -L integration-clientarrays-split --no-tests=error -j 1 \
> "${RUNNER_TEMP}/clientarrays.txt" 2>&1 || rc=$?
tail -5 "${RUNNER_TEMP}/clientarrays.txt"
if ! grep -rqF "run-ahead ARMED" "${logs}"/*ClientVertexArrayScenario*.log 2>/dev/null; then
# kMGPipeP5eRunAheadReady is false on this head: the client is lockstep, vi's arm is
# alive and these entries are the positive control they were registered as.
if [ "${rc}" -ne 0 ]; then
echo "::error::integration-clientarrays-split is red WITHOUT run-ahead armed. Under lockstep the client-memory array path is legal and vi keeps it working, so this is a real regression in that arm and not ID-82's refusal."
exit 1
fi
echo "integration-clientarrays-split is green: run-ahead is not armed on this build, so ID-82's refusal is unreachable"
exit 0
fi
if [ "${rc}" -eq 0 ]; then
echo "::error::integration-clientarrays-split went GREEN with run-ahead ARMED. ID-82 refuses a client-memory vertex array under run-ahead by name, so a green run means the refusal did not fire and the server dereferenced a client pointer from an unbarriered record. If P8 has landed the staged form, delete this step and fold the entries back into integration-split."
exit 1
fi
marker='Fatal{UnmigratedVerb, "'
if ! grep -rhoE 'Fatal\{UnmigratedVerb, "(Multi)?DrawArrays\+CLIENT_ARRAYS"\}' \
"${logs}"/*ClientVertexArrayScenario*.log 2>/dev/null | sort -u | grep -q CLIENT_ARRAYS; then
echo "::error::integration-clientarrays-split is red but no private log carries ${marker}...+CLIENT_ARRAYS\"} - the lane failed for some OTHER reason, which is a defect rather than the expected-red control"
grep -rhoE '(Fatal|Admitted)\{[A-Za-z]*, "[^"]*"\}' "${logs}"/*ClientVertexArrayScenario*.log 2>/dev/null | sort | uniq -c | sort -rn | head
exit 1
fi
echo "integration-clientarrays-split is red by design on:"
grep -rhoE 'Fatal\{UnmigratedVerb, "(Multi)?DrawArrays\+CLIENT_ARRAYS"\}' \
"${logs}"/*ClientVertexArrayScenario*.log | sort -u
- name: Upload strict lane logs
if: always()
uses: actions/upload-artifact@v7