mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
1ef27dcd5c9ece36336ffaf6badd02787cea62c5
137
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d49df3549f | [MG_Backend, MG_State, scripts] (P7): retire the texture legacy-arm scope and tag the p7-magma remainder P13 | ||
|
|
e751b07baa | [scripts] (P7): restore the executable bit the CI fix package dropped from junit_tally.py and stub_ctest.sh | ||
|
|
877c531a0d | [CI] (P7): tighten renamed CI titles | ||
|
|
072ea1b832 | [android-plugin, scripts] (P7): a passed APK replay whose device went offline before its logs were copied asks for the infrastructure retry | ||
|
|
b13045918a | [CI, scripts, tools] (P7): the pull control strips ctest -V's line prefix, retrace-split pins lavapipe, and the retrace summary reads role logs | ||
|
|
f1ce655b42 | [MG_IntegrationTest, scripts] (P7): the Tcp TextureUploadShape entry holds the mobilegl-tcp lock, and the lane tools refuse any supervisor entry that does not | ||
|
|
d1549cba57 | [scripts] (P7): the TCP lane supervisor starts headless like every other server the harness reaches | ||
|
|
9fd768d493 | [MG_Backend, MG_IntegrationTest] (P7): bound wire descriptor sets within long frames | ||
|
|
1ab62ece4c |
[ci] (P7): the parity exception list names M2 round 2's fourth Reclaim case
- ADrawAfterTheEarlyReclaimFollowsTheNewStoreNotTheMemoizedHandle rides the same split/spawn fixture as the three gauge cases and the tcp arm does not carry it (magma-m2.md §9.3); the integration tree keys this list by exact tail, so the fourth name goes in beside the three |
||
|
|
3b8bf9ec25 |
[scripts] (P7): the pull-library control refuses an empty grep -F pattern in EVIDENCE, and the stub ctest is executable again
- every line of EVIDENCE is a grep -F pattern and an empty line matches everything: a trailing newline or a blank line between the two sentences would turn hole 2 into "any red will do". The smoke's "red without the transport-resolution message" case catches that (22/23), but only when somebody runs it; a `case` after the assignment now refuses a blank line or a leading/trailing newline with ::error:: and rc 1, before the selection is counted or the library is swapped. The red-check's perturbation line is untouched; smoke 23/23 - scripts/ci/testdata/stub_ctest.sh went 100755 -> 100644 in the round-2 commit that added its retrace-evidence-nolog mode (a Windows-mount artefact); restored with `git update-index --chmod=+x`. The smoke copies it and chmods the copy, so nothing ran differently |
||
|
|
bd849b2821 |
[tools] (P7): the audit's block walk is fail-open only for the disaggregated guard, and an indented #else stops it
- stepping over `#endif` accepted a log that is compiled out: `#if 0` / `MGLOG_W(...)` / `#endif` / `Count(...)` read as logged, and so did a log under `#ifdef MOBILEGL_VERBOSE_DECLINES` - a Count that counts every time and logs in no shipped build - the walk now counts the `#endif`s it crosses; a same-indent log met with one outstanding counts only if every opener enclosing it, reached by continuing upward, is the whole-line `#if MOBILEGL_BUILD_DISAGGREGATED` (`&& X` is not it). `#if`/`#ifdef`/`#ifndef` with no `#endif` outstanding is the Count's own guard and is still stepped over, so the column-0 `#if/#endif` fixture stays green; the comment says the walk is fail-open for that one guard and nothing else - `#else`/`#elif` stopped the walk only at column 0, as a line of lesser indentation; one at the Count's own indentation walked straight through to the log above it. PP_STOP now returns False at any indentation, before the indent test - two red fixtures, both green on the round-2 audit: "log only under a #if 0 above the Count" and "log only on the other side of an INDENTED #else at the Count's indentation"; 16/16, the tree stays 53 / 53 / 0 |
||
|
|
8c8fc31952 |
[MG_Remote, MG_Test, ci] (P7): the token compare runs a fixed 64-byte width, an ignored window ask is logged once, a nonce that could not be minted is refused by name, and a garbage first frame while busy is MalformedHello rather than Busy
- AuthToken.h: ConstantTimeTokenMatch loops kAuthTokenCompareBytes (64) iterations with both operands read as zero past their ends - its trip count no longer tells a peer the configured token's length; a token longer than 64 is still compared to its last byte (SocketTransportTest pins the 70-byte case)
- ServerSession.cpp: an ask in Hello.linkTerms above the granted terms logs one MGLOG_W naming both sides ("the ask is ignored and the session is server-sized"); the production client asks for nothing, so a session that was never mis-configured never logs it; SessionHandshakeTest's 64 GiB case requires the line (red before: absent)
- ServerSession.cpp: a MintNonce failure sends Refuse{LinkTerms} "stream data plane unavailable: the server could not mint a data nonce" before returning the fault it is (still exit 67, still counted) instead of a bare close
- ServerMain.cpp: a first frame with the wrong magic or over 1 MiB while a session is live is Refuse{MalformedHello} "first frame is not a control frame", drained before the close so the refusal is not RST away; Busy stays the answer for a well-formed frame that is not a DataBind
- tcp_supervisor_smoke.py: garbage_first_frame_while_busy (magic XXXX on a live session -> code 8; red before: code 7)
- fatal census unchanged: 79 abort sites, 3 refusal words (the new refusals go through the enum, not a literal)
|
||
|
|
c69d8dfdc8 |
[MG_Remote, MG_Test, ci] (P7): sha256(protocol.fbs) is pinned to MOBILEGL_PROTOCOL_CONTROL_REVISION, so a control-schema edit without a bump is red in the unit lane and in flatc-check instead of a silently absent field
- the revision is a hand-bumped integer mixed into wireFingerprint and nothing tied it to protocol.fbs's content; scripts/ci/protocol_revision_pin.py holds {revision -> sha256(protocol.fbs)} in protocol_revision_pins.json and refuses a schema whose digest is not the current revision's, or a revision with no row
- registered as ProtocolSchema.RevisionPinsDigest (label unit, MG_Test/Wire/CMakeLists.txt, --self-test proves both perturbations red before it says green) and as a step of CI's flatc-check job, the one that regenerates the header on every schema edit
- --write records a bump's row and refuses to re-pin an existing revision to a different digest, which is what a schema edit without a bump looks like
- mg_protocol_base.h says where the pin lives beside the revision it pins
- red-once: protocol.fbs touched with one trailing comment, revision left at 1 -> "protocol.fbs has sha256 a7b5c7fb... but MOBILEGL_PROTOCOL_CONTROL_REVISION is still 1, which is pinned to 7fc859f7..." rc=1; restored, green
|
||
|
|
0293aebb17 |
[MG_Remote, ci] (P7): a bound session closes its data-connection source, so a later DataBind is refused by name instead of queued into a child that stopped reading, and the single-session listener closes with it
- ServerMain.cpp: RunSession takes the descriptor its data-connection source reads from (the child's hand-off end under --serve, the listener itself without it) and closes it the moment Accept returns; the source object goes with it
- the supervisor's hand-off send is MSG_DONTWAIT (FdPassing::SendFd dontWait), so a peer that stopped reading answers at once; "peer gone" on a datagram pair (ECONNREFUSED, ENOTCONN) is an answer the caller names, not a logged fault
- before: every DataBind after the bind sat in the child's receive queue with no reply, its TCP connection held open until the session ended, and past the queue limit (net.unix.max_dgram_qlen 10 on the phone; ~288 datagrams of sender buffer on this host) the supervisor blocked in sendmsg for the rest of the session - no accepts, no Busy, no reaping
- before, without --serve: the listener stayed open after the data connection bound, so a second client or a retry completed a TCP handshake nobody would accept and waited out its 20 s connect budget instead of the ECONNREFUSED it got before PH-7 (4)
- tcp_supervisor_smoke.py: data_bind_after_bound (12 extra DataBinds on a bound session each get Refuse{Authentication} "data connection could not be handed to the live session", and a fresh control connection is still Busy) and single_session_listener (a connect after `ready` is ECONNREFUSED); connect_control retries ECONNREFUSED at startup for pair() and held_session() alike
- red-once at da313010: smoke TimeoutError on the first extra's receive; probe with qlen+2 fire-and-forget DataBinds: 288 queued silently, then the supervisor stopped accepting (fresh control: connect timed out) while still alive; single-session connect after ready succeeded
|
||
|
|
9328bdc735 |
[MG_Backend, MG_Util, MG_Test, MG_IntegrationTest, scripts] (P7): integration-magma-split and -spawn carry MagmaWireReclaimScenario, which reads the server's wbuf[] gauges and reds on a wire arm that keeps orphaned buffer stores until the frame ends
Rule J's red-once for M2. The server role's VkBufferManager publishes four PipeStats gauges (push builds only, so the pull image is untouched): wire buffer records alive, and the run maxima of live wire VkBuffers and of parked bytes, plus the watermark's forced-sync count - maxima because the defect lived inside one frame and a swap-time sample reads after the frame boundary's own sweep. Two cases, each inside a single frame: 1024 undrawn respecifies of one 4 KiB buffer (live peak <= 4 x wire buffers), and 48 respecify-and-draw rounds of a 1 MiB store under the lane's MOBILEGL_IPC_WIRE_DEFERRED_MB=8 (parked peak <= budget + one store, every strip its own colour). Red at base (ec46a550's defer path, counted): 1025 vs 4 live, 49,287,168 vs 9,437,184 bytes and 49 vs 11 live, on both arms; green after: 1 live, 9,437,184 bytes / 9 live with 5 forced syncs. The knob's negative control (=0) reds the second case with the same 49,287,168 bytes. Inproc and spawn only: the tcp server is the lane-wide fixture supervisor, whose environment and log the entry cannot reach - named in spawn_lane_parity.py as MAGMA_NOT_ON_TCP (the ID-P7-14 shape), and PipeStatsTest pins the four short names. |
||
|
|
46bda06226 |
[scripts] (P7): the pull-library control accepts the no-client-log sentence a pull build has produced since the per-role log rename
- retrace_pull_library_control.sh required run_trace_case.cmake's "never reported resolving it", the marker-search sentence. Since P6's one-log-per-role rename a pull library never reaches that search: it has one role and writes MOBILEGL_LOG_FILE_PATH unchanged (output/mobilegl.log, Log.h's pull arm of RoleLogPath), the runner reads output/mobilegl.client.log and stops one check earlier with "the run wrote no <client log>, so there is no evidence the transport ever resolved" - so the control's hole-2 check refused its own red and the step exited 1 on every pull-library run - measured on this tree with the real ctest, build-linux's pull library over build-split's frozen split library, SPLIT_TRANSPORT=inproc: control rc 1, "::error::the split retrace went red (ctest exit 8) ... never says the library did not resolve the transport", the runner's fatal at the no-client-log check. With this change the same run passes for its own reason on both inproc and spawn - EVIDENCE carries both sentences as grep -F's newline-separated patterns, so the evidence line the red-check perturbs is unchanged; both are the transport-identity assertion refusing the same library for the same reason, and neither is a loader failure, a missing fixture, a timeout or an SSIM drop - stub_ctest.sh gains retrace-evidence-nolog, the no-client-log fatal CMake-wrapped across lines the way the real one arrives; control_smoke_test.sh expects it to PASS (23/23); the red-check still reds "red without the transport-resolution message" |
||
|
|
b0d4d730ba |
[tools] (P7): the audit's block walk stops at a same-indent exit and steps over a column-0 #if
- a same-indent `case`/`default:`/`break;`/`return`/`continue;`/`goto`/`throw` line between a log and a bare Count ends the walk: control cannot flow from that log to the Count, so it is not the Count's log. A `case 1: MGLOG_W; break; case 2: Count` switch with its labels at statement indentation, and a log above a `return` with the Count under a same-indent label, both read as logged before - `#if`/`#ifdef`/`#ifndef`/`#endif` lines are passed over: a log and its Count that straddle a `#if MOBILEGL_BUILD_DISAGGREGATED` are one block on both sides of the preprocessor, and the column-0 line ended the walk for no defect. `#else`/`#elif` still end it - a log on the other side of one is in a different build, not this one - four fixtures: same-indent return (red), same-indent switch (red), log across a #else (red, and red on the previous audit too - it pins that #else still stops), Count under its log across #if/#endif (green; a false red before). 14/14 fixtures; the tree stays 53 / 53 / 0 |
||
|
|
576fc09a31 |
[tools] (P7): the audit's strip reads a prefixed character literal as a character, not as a digit separator
- L'"', u'"', U'"' and u8'"': the `'` after an identifier character was taken for a C++14 digit separator, the `"` inside it opened a phantom string, and the rest of the line was blanked - a site on that line vanished and its row read as NO SITE (fail-closed: a false red) - CHAR_PREFIX accepts a u8/u/U/L prefix before `'` the way RAW_PREFIX does before `"`, with a non-identifier character (or the start of the text) in front of it, so a real separator (0xAB'CD, 1'000) is untouched - self-test fixture with L'"' and u8'"' ahead of two AT sites on their own lines: rc 0; it was rc 1 on the previous audit. The tree has no prefixed character literal today (53 / 53 / 0) |
||
|
|
9d5f5012c7 |
[tools] (P7): a site's log is a statement that begins with MGLOG_W/E, not a line that mentions one
- the wire declines audit's LOGGED pattern was unanchored, so a guarded one-liner at the
Count's indentation (`if (g) MGLOG_W("x");`, `g ? MGLOG_W("x") : (void)0;`) counted as
the site's own log and the site read as logged - a decline counted every time but logged
only sometimes, which is the unlogged site the check exists to refuse
- anchored to the statement start; the block walk matches the line, not searches it
- self-test fixture "guarded one-liner log at the Count's indentation" (both shapes) reds
with the NO_LOG sentence; it was green on the previous audit. The tree stays 53 / 53 / 0
|
||
|
|
ce83651349 | [MG_Remote, MG_Test, ci] (P7): a Hello asking for 64 GiB windows is welcomed with the server's own terms and its session child never reaches 64 GiB, pinned in process and on the TCP supervisor | ||
|
|
20ab14daf8 | [MG_Remote, MG_Test, ci] (P7): a TCP session's data connection is bound to its authenticated control connection by a 128-bit Welcome.dataNonce instead of by arrival order, so a reordered or stale data connection is refused by name and the wire fingerprint moves with the control schema | ||
|
|
8fa1821ab2 | [MG_Remote, MG_Test, ci] (P7): one constant-time token comparison serves both server policy sites, a configured token shorter than 16 bytes refuses the listen by name, and CI builds flatc so the TCP supervisor smoke runs and must pass | ||
|
|
266d6a32f8 |
[tools] (P7): the wire declines audit carries a self-test whose fixtures must red, and the CI step runs it before the tree audit
Fable review of the B3 rework, should-fix: the audit had no negative
control, so a green run could not say it would have been red. It now takes
--self-test, which writes each inline fixture as a one-file renderer tree in
a temp dir, runs the audit on it and checks both the rc and the line the
audit must print (so a red is red for the fixture's reason):
comment-only site (//) -> rc 1, "has NO SITE"
comment-only site (/* */) -> rc 1, "has NO SITE"
string-literal site -> rc 1, "has NO SITE"
other-branch log -> rc 1, "with no MGLOG_W/E in its own block"
nested-branch log -> rc 1, same
log only in a /* */ comment above -> rc 1, same
nearest log is MGLOG_D -> rc 1, same
good sites (AT form, bare Count under
its own MGLOG_E_ONCE, def row with a
trailing comment) -> rc 0, "0 unlogged, 0 unknown"
8/8, rc 0. Mutants: with the strip disabled 5 of 8 fail (the four
comment/string reds go green and the good fixture's commented row is
lost); with the old 8-line window in place of the block walk 2 of 8 fail
(other-branch, nested-branch). Against the audit as it stood at aab01275,
six of the seven red fixtures passed and the good one failed.
.github/workflows/test.yml: the "Wire declines audit (B3)" step runs
--self-test and then the tree audit, the way the next step runs
trace_cases.py --self-test-transport-matrices before it computes matrices.
|
||
|
|
78269b2677 |
[tools] (P7): a bare decline count is logged only by a warning-or-error line in its own block, and a def row with a trailing comment is still a row
Fable review of the B3 rework, should-fix: the 8-lines-above MGLOG_W/E window
was branch-blind - a Count() in `if (x == 2) { ... }` whose only log sat in a
preceding `if (x == 1) { ... }` passed, as did a log in a nested branch just
above. All 12 bare sites in the tree are under their own line today, so this
was a gate hole, not a present defect.
has_own_log() walks upwards from the Count line (still capped at 8 lines):
blank and deeper-indented lines (a log's continuation lines, a nested block)
are passed over, only a line at the Count's own indentation can be its log,
and the first line indented less than the Count - the block's opening, a
sibling's `} else {` - ends the walk.
WireDeclines.def is now read through the same comment/string strip, and ROW
tolerates spaces inside the parentheses: `MGL_WIRE_DECLINE(Name) // note`
used to fail `\)\s*$`, dropping the row, and its real site was then
reported as naming no row.
Tree: 53 rows, 53 with sites, 53 sites, 0 unlogged, rc 0 (unchanged).
Fixtures the previous commit passed and this one reds: other-branch log,
nested-branch log (rc 0 -> 1); a def row with a trailing comment plus its
site (rc 1 -> 0).
|
||
|
|
88599fc6f6 |
[tools] (P7): the wire declines audit matches sites and logs on code alone, so a commented-out or quoted site is no site
Fable review of the B3 rework, must-fix: a row was "sited" by any line the AT_SITE / COUNT_SITE regex matched, including a // comment, a /* */ block or a string literal - `// MGL_WIRE_DECLINE_AT(GhostRow, "...");` satisfied the audit for a row nothing counts, and an MGLOG_W inside a comment above a bare Count() satisfied the log rule. wire_declines_audit.py now blanks //...$ (with backslash-newline continuation), /* ... */, "..." and '...' (raw strings R"d(...)d" and C++14 digit separators handled) out of each source before any match. Every character but the newline becomes a space, so the text keeps its length and line count and each report still cites the real line. Tree: 53 rows, 53 with sites, 53 sites, 0 unlogged, rc 0 (unchanged). Fixtures that the previous audit passed and this one reds (rc 1): a comment-only site (//), a comment-only site (/* */), a string-literal site, a log only in a /* */ comment above a bare Count. The branch-blind window and the .def trailing-comment row are the next commit. |
||
|
|
4db17d58c6 |
[MG_Backend, MG_IntegrationTest, scripts] (P7): a declined multisample depth/stencil shape is decided once before any aspect runs, so an erroring blit writes nothing, and the shader resolve arm gets a flipped knob twin
- BlitWireFramebuffers runs colour first. A scaled COLOR|DEPTH blit out of a multisample framebuffer scaled and wrote its colour and then recorded INVALID_OPERATION on its depth, and an X-mirrored one mirrored its colour and left its depth alone - partial effects GL 18.3.1 does not allow. The shape decline (scale, X mirror, cross-format Y mirror) moves into DeclineWireDepthStencilResolveShape, which BlitWireFramebuffers asks for every depth/stencil aspect that would take the multisample resolve arm before any aspect runs; ResolveWireDepthStencil asks it too for any other caller. Default read/draw framebuffers are left to the lambda (a default read is never multisampled; a default draw behind one is the region Fatal, and resolving it early would move its write index).
- The X decline and the cross-format Y decline get their own MGLOG_E_ONCE sites; one site used to cover both, so after the first X decline a cross-format Y decline logged nothing.
- An empty rectangle on one side only (64x48 onto 0x48) is a size mismatch and now takes the scale decline (INVALID_OPERATION) instead of returning silently; empty on both sides stays a silent no-op.
- DirectVulkan.{Split,Spawn}.MsFlip1. forces MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE=1, so the shader arm min-corner rectangle under a flip runs on this host; split+spawn only and named in MAGMA_SERVER_ENV_KNOB_NO_TCP.
- spawn_lane_parity.py: every server-env-knob tail must match exactly one split key, so a dead or over-broad tail fails the gate instead of riding silently.
- The flipped-resolve case gains a COLOR|DEPTH scale leg (error, colour untouched, depth untouched) and an empty-destination leg (error, depth untouched).
- Red-once, each on split + spawn (+ tcp MsFlip.) and restored: pre-pass disabled -> all five MsFlip/MsFlip1 entries fail "the declined COLOR|DEPTH scale must not have written its colour either" (read {255,0,0,255}, want {0,0,255,255}); round-1 silent empty-side return -> all five fail the empty-destination leg (error 0, want 1282); shader arm handed sx0/sy0 instead of the min corner -> MsFlip1 fails on both arms ("768 of 768 depth values differ from 0.75", "928 of 3072 stencil values are wrong; first at (20, 4): got 255, want 99") while MsFlip. stays green; a dead ".MsFlip2." tail -> parity rc 1 "matches 0 split entrie(s)".
- The split once-sites have no lane red-once: the cross-format Y decline needs a device whose renderbuffer and texture D24S8 map to different VkFormats, which lavapipe is not.
|
||
|
|
75a64ce0da |
[tools, docs] (P7): the parity script keeps one server-side-knob list after the B3 rework merge, and magma-b3.md names it
The B3 rework's parity hunk and B2's round-1 hunk described the same asymmetry
under two names; the merge kept B2's compare_arms(no_tcp=) and added .StaleSerial.
to MAGMA_SERVER_ENV_KNOB_NO_TCP. One line of the package tree's other mechanism
(`not_on_arm = not_on_arm or {}`) survived outside the conflict hunks and would
have been a NameError on the first run; it goes, and the note's two mentions of
MAGMA_NOT_OVER_TCP now name the list that exists.
|
||
|
|
b0c6af3168 |
[MG_IntegrationTest, tools] (P7): the stale-serial red-once is registered on split and spawn only, and the parity gate names it with the other server-side knobs
MGITEST_MAGMA_FORCE_STALE_BUFFER_SERIAL is read by the server. The tcp arm's server is the lane fixture (scripts/ci/tcp_server_fixture.py), started once from its own environment, so an entry-level ENVIRONMENT never reaches it: DirectVulkan.Tcp.StaleSerial.* ran the unforced case under a name that claimed the knob and could never red (review ID-P7-34, item 1). The entry is now registered only when the arm is Split or Spawn, and spawn_lane_parity.py grows a second named asymmetry beside MAGMA_INPROC_ONLY: MAGMA_NOT_OVER_TCP, key prefixes the reference arm has and the tcp arm does not by name. It comes off the reference for the tcp arm alone, so the same entry missing from spawn is still an error. B2 adds its own knob entries to the same tuple in its tree. integration-magma-tcp 71 -> 70 entries (68 cases + the two fixture entries); split 90, spawn 69 unchanged. spawn_lane_parity.py build-split rc 0; tcp_lane_tools_test.py 6/6. Integrator merge onto pipe: B2's round-1 mechanism (`mglItestServerEnvKnobArm` in CMake, `compare_arms(no_tcp=)` in the parity script) already covers this shape, so `.StaleSerial.` joins MAGMA_SERVER_ENV_KNOB_NO_TCP instead of the separate MAGMA_NOT_OVER_TCP the package tree introduced. |
||
|
|
b8d10d0730 |
[MG_Backend, tools] (P7): every WireDeclines.def row has a site and every site a warning-or-error line, and a tree-only audit fails the job when one does not
The B3 review (ID-P7-34) counted 12 of the 52 rows with no site at all - TexViewFormat, TexNoApplierRecord, TexRecordDeadOrStale and the nine Shape* rows were declared and never counted - and ten sites that counted with no (MGLOG_D included) line, so "a name, a tally and a decline line" did not describe the tree. - SyncWireTextureShape: all nine Shape* exits now count; the ViewOf exit and the preserve-flush exit were bare `return false` and are now MGL_WIRE_DECLINE_AT; the image-flags exit logged only MGLOG_D, which a Release build compiles away, and is promoted likewise. - The preserve-copy exit was the one Shape exit with no row: appended as ShapePreserveCopyFailed (rows are append-only), 53 rows. - SyncTextureResourceByHandle / UploadPendingWireLevels: the count-only sites without a log of their own are promoted to MGL_WIRE_DECLINE_AT; the ones already under a W/E _ONCE line keep that line and gain the count. - scripts/ci/wire_declines_audit.py: fails on a row with no site, a site naming no row, or a bare Count() with no MGLOG_W/E within 8 lines above it. WireDeclineTally.h (the macro's definition) is not a site. Wired into the job that runs the fatal census. Audit before: 52 rows, 40 with sites, 10 unlogged under the W/E rule (rc 1). After: 53 rows, 53 with sites, 0 unlogged (rc 0). Forced red (ShapeNoVkFormat made true for 1x1 textures, reverted): Split.Fm.F1WireScenario.VertexIdSampler... fails on pixels with ShapeNoVkFormat=2 / TexShapeSync=2 in the shutdown tally. |
||
|
|
cc3c18c578 |
[scripts, docs] (P7): magma-b2.md counts the baseline as 73 + 11 + 2 + 2, carries the review round's §12 lines and gates, and the ratchet baseline names the tree that measured 173
ID-P7-31 review, note 3 and nits.
* §0's preamble: the +4 over package B's 84/63/65 is not "package A landing after
B" - A landed BEFORE B and is +2 (magma-a.md:151-153); package C is the other +2
(magma-c.md:59-61). 73 + 11 (B) + 2 (A) + 2 (C) = 88/67/69.
* §2.3 / §2.5: MsResolve1 is split+spawn only; the day-of +3 on tcp is marked as
superseded.
* §2.7 (the server-side knob has no tcp arm, measured) and §2.8 (flip mirrored,
scale declined, X / cross-format mirror declined; three red-once lines).
* §6: the lines for CONTRACT-P7 §12 - the scaled second leg is unclipped
(VUID-vkCmdBlitImage-dstOffset-00248/00249, shared with the monolith);
MagmaWireFatal("multisample-resolve-region") for a source rect outside the read
buffer, where GL promises undefined values rather than an error; the 1->N
identical-rect decline declines a legal shape (18.3.1 sample replication) because
the monolith's own observable is a VU violation; the tcp lane cannot carry a
server-side knob; X and cross-format Y mirrors of a depth/stencil resolve decline.
* §7: the review round's gates - magma 94/73/70, full-split 525, unit 2423, parity
RC 0 naming the five MAGMA_SERVER_ENV_KNOB_NO_TCP entries, census 79, ratchet 173,
G1 .text 0xa52203 with 0/0 symbol drift, @P7 19 comment lines.
* link_ratchet_baseline.txt: `base commit` points at 6af422b3, the tree that
measured 173, not 4bee1313.
The "@P7 = 24 lines" nit needed no edit: the note already reads 19 at 6af422b3, which
is what the tree measures.
|
||
|
|
9fed478dfd |
[MG_IntegrationTest, scripts] (P7): a server-side magma test knob is registered on split and spawn only, and the parity gate names the five entries tcp cannot carry
ID-P7-31 review, should-fix 1. Every MGITEST_MAGMA_FORCE_* knob is read BY THE SERVER (the getenv readers in WireFramebuffer.inc run on the apply thread), and a ctest ENVIRONMENT property only reaches the process ctest starts - the client. Inproc runs the server in that process and ServerSpawn.cpp copies ::environ into the spawned child, so both arms see the knob; the tcp arm's server is the lane-wide TcpServer.Start fixture, started once from scripts/ci/tcp_server_fixture.py's own os.environ, and nothing a per-case property says reaches it. The tcp copy of each knob=1 entry ran the DEFAULT arm under a name claiming otherwise. Measured, not deduced: a temporary fatal in each of the three readers killed all five knob=1 entries on split and on spawn and left all five green on tcp. So ShaderMip1, ShaderMip2, DepthMip, DefaultBlitShape1 and MsResolve1 are registered on split+spawn only (the first four are package B's pre-existing vacuity of the same shape). The knob=0 twins DefaultBlitShape0 / MsResolve0 keep their tcp entries: zero is the default and means the same thing on every arm. spawn_lane_parity.py names the exception, following ID-P7-14's MAGMA_INPROC_ONLY: MAGMA_SERVER_ENV_KNOB_NO_TCP, applied through a new compare_arms(no_tcp=) that drops the keys from the tcp comparison ONLY - folding them into inproc_only would stop requiring them on spawn, which is where they do most of their work. |
||
|
|
3c2867d34d |
[MG_Backend, scripts, docs] (P7): in a disaggregated build the monolith arm blits and mips with the baked modules, and the ratchet's p7-magma bucket falls to 88
CONTRACT-P7 §5.2's (B'), which §4.2 needs.
WHAT MOVES. In a disaggregated build the monolith arm now drives the SAME baked
modules the wire arm does:
* InitializeBlitResources / InitializeDepthMipmapResources return true - there is
nothing to build on any transport;
* TryBlitToDefaultFramebufferWithShader turns its two BlitImageBindings into
WireImages and calls BlitWireColorToDefault (WireColorBlit.inc);
* GenerateDepthMipmapWithShader loops GenerateWireDepthMipLevel
(WireDepthMipmap.inc) and hands the image back in the finalLayout its caller
promised;
* GetOrCreateBlitPipeline, the three GLSL strings, the eight kHidden* ids and the
frontend members of BlitResources / DepthMipmapResources compile out.
The `#else` is the pull build's code, statement for statement.
WHY AN `#if` AND NOT A RUNTIME BRANCH - this is the whole of §4.2. P5f fv already
gave both initializers a non-monolith early return, and the ratchet counted the
symbols anyway, because a reference is a reference whether or not the branch runs.
And the MEMBER has to go with the construction: a SharedPtr member's destructor is
itself a reference to ~ProgramObject.
THE BUCKET TABLE (scripts/link_ratchet.py --bucket, build-split):
bucket before after a6
p6-core 11 11 6
p7-magma 101 88 101
p3b-p4b-espryt 13 18 14
both-backends 61 56 60
total 186 173 184
p3b-p4b-espryt's +5 is not a regression: those five MOVED out of both-backends
because DirectVulkan stopped referring to them and only DirectGLES still does.
Thirteen symbols went away outright, and they are exactly the three classes §4.2
names: ProgramObject::{AllocateLifetimeId, AttachShader, Link, ~ProgramObject},
SamplerObject::{SetLodRange, SetWrapR, SetWrapS, SetWrapT} and
ShaderObject::{Compile, DropCompileNode, JoinPendingCompile, ReleaseCompileNode,
SetShaderSource}. Re-baselined in this commit with --write-baseline; the 7 `# P13`
annotations carried over.
§4.2's "down to 0" DOES NOT HOLD, and the gap is not (B') left half-done - it is
that 88 of the 101 were never about the hidden programs. 62 come from
UniformManager.cpp.o and 14 more from VkSamplerManager.cpp.o: the MONOLITH
descriptor binder and sampler cache reading the application's own GL texture and
sampler objects (TextureObjectBase 35, TextureObjectWithOneMipmap 20 with its
vtable and typeinfo, SamplerObject's fourteen getters). Under a transport
SetupDraw branches to SetupWireDraw and not one of those lines runs - but that
branch is a RUNTIME one, which ID-P7-5 deliberately leaves to the optimisation
phase. notes/p7/magma-b2.md §4.3 names all eleven referring-object groups and what
each is.
NONE OF THEM IS ANNOTATED `# P13`, on purpose: that mark is for a symbol that
cannot fall without moving pull `.text`, and nothing above has shown that.
UniformManager's and VkSamplerManager's monolith arms are pull-build code, and
`#if`-ing them is the same operation this commit performed on VulkanRenderer.cpp.
They are wave 3's work, not P13's boundary problem, and marking them P13 early
would record an untried thing as a tried-and-impossible one.
Gates: integration-gpu 1705 (every monolith `DirectVulkan.` entry is in there),
integration-magma-split 93, -spawn 72, -tcp 74, integration-magma-full-split 524,
ctest -L unit 2423, all green; fatal_census 79 abort sites / 44 family words / 0
unmarked; spawn_lane_parity green; link_ratchet --assert-monotone unchanged at 173
against the re-baselined file, and --self-test OK.
RETRACE, which is this slice's load-bearing reading because the monolith arm
changed implementation: OpenRA.DirectVulkan (monolith) ssim 1.000000,
mismatchPixels 0, twice; OpenRA.DirectVulkan.SPLIT ssim 1.000000, 0. The whole
DirectVulkan matrix is 39/40 monolith and 38/39 split, and both reds are the SAME
case, minecraft-1.21.4-fabric-iris-iterationrp-in-world (ssim 0.027915), which is
PRE-EXISTING - it fails identically on ~/w7/p7-magma-b (this branch's parent),
because it needs CONTRACT-P7 §2.4's three iterationRP knobs and those are exported
by the CI job rather than by the ctest entry.
G1 pull .text 0xa52203, nm --defined-only identical to p7-before/pull-syms.txt
(30570 lines, 0 diffs).
Device debt: the monolith arm in the Android disaggregated package now runs the
baked blit, and its ROTATE_90/180/270 geometry has never executed - every surface
on this host is IDENTITY. notes/p7/magma-b2.md §5 lists it with the package's three
other device items.
|
||
|
|
394df89237 |
[scripts, ci] (P7): the memo purity gate asserts its own anchors and allow-list, and stops calling a policy exemption an absence
Rework round 3 of 4 after the D2 review (fable, ID-P7-8). Three defects, each of a kind the gate could not have reported about itself. (a) TWO STRUCTURAL SELF-CHECKS. family_spans() returned whatever matched and nothing ever asserted that each of the five FAMILIES anchors found its declaration, so a renamed struct would drop a whole family while every rule kept passing. And an allow-list entry no rule can consult documents a carve-out that is not happening - a claim about the tree that nothing verifies. main() now fails on either, naming the anchor or the entry and saying which of the two repairs is wanted. Both are exercised: renaming an anchor and adding a dead entry each red the gate. (b) THE DOCSTRING AND THE test.yml COMMENT WERE WRONG about what the guards mean. MOBILEGL_PIPE_LEGACY_MEMOS defaults ON (CMakeLists.txt:43) and no job here clears it, so CI split builds DO compile those arms - TwinLookupMemo (DirectGLES.cpp:114) sits inside one and is compiled into every lane this repo runs. The rule is "the legacy arm MAY KEEP pointer keys", a policy exemption; only !MOBILEGL_BUILD_DISAGGREGATED is code a split build genuinely never sees. Both now say so. (c) FRONTEND HAD NO LEADING WORD BOUNDARY, so BackendSamplerObject* matched SamplerObject and the gate reported the memos' backend VALUES as frontend keys - which the first version answered with two allow-list entries, i.e. it documented a false positive instead of fixing it. (?<!\w) added, with controls both ways: the backend twins must stay green and the qualified MG_State::GLState::ProgramObject* must still match. The allow list therefore goes from six entries to ONE. Four were dead on arrival - two false positives now fixed at the source, one naming a typedef with no frontend type in it, and const void* program / Uint64 programLifetimeId, which no rule could ever consult because void is not in FRONTEND and neither line calls GetLifetimeId(). The ResolvedTextureBindingMemo monolith key those last two described is still deliberate and still there; it simply never needed an exemption, and saying it did was misleading. What remains is the twin registry's UnorderedMap<StateObject*, Entry>, which really is suppressed and really is the pull build's only arm. |
||
|
|
6567bc1e16 |
[scripts, ci] (P7): a purity gate for Espryt's re-keyed memo families
P3b/P4b deepening, landing under the P7 program (PLAN-PH-P34B-P7.md 1.2, wave 2-D package D2): "一条纯度 grep 门:split 构建下这些 memo 键里不得出现前端指针类型;接 CI". scripts/ci/espryt_memo_purity.py, a sibling of link_seam_purity.py in the same style: a hard-coded source list, a code_only() comment strip, (pattern, message) rules, and a --self-test that runs the negative controls and then the real scan in one invocation - which is what lets test.yml pass only --self-test and still get the gate. Wired in next to link_seam_purity.py. It scopes the rules to the BRACES of the families the plan names - ResolvedTextureBindingMemo, SamplerPassMemo, UnitSamplerLookupMemo, TwinLookupMemo, StateBackendObjectRegistry (the program registry and its five siblings) - plus the image sweep, which is seven file statics rather than a struct and is matched by name. Scoping matters: these two files pass frontend pointers around legitimately in hundreds of places, and a file-wide grep would be a list of exceptions rather than a gate. Guard-awareness is a small conditional walker, not a preprocessor: it recognises #if MOBILEGL_PIPE_LEGACY_MEMOS, #if !MOBILEGL_BUILD_DISAGGREGATED and the #else of #if MOBILEGL_BUILD_DISAGGREGATED, which is every spelling these files use, and says so in the docstring. Six allow-list entries, each carrying its one-line reason. The two that matter: StateBackendObjectRegistry's UnorderedMap<StateObject*, Entry> and ResolvedTextureBindingMemo's type-erased `const void* program` are the PULL build's only arms - deleting them moves pull .text and fails G1's 0/0/0/0, so they retire with the pull path (P13), not here. The other four are memo VALUES rather than keys. Seven negative controls turn red; four positive controls stay green, including a LEGACY_MEMOS arm, the #else of a DISAGGREGATED arm, the allow-listed type-erased key and a frontend pointer outside every memo family. Verified once more by injecting a fresh unguarded ProgramObject* field into the real ResolvedTextureBindingMemo: the gate reddens and names it. |
||
|
|
fdd611e83d |
[MG_Backend, MG_Test, MG_IntegrationTest, scripts, docs] (P7): the depth mip chain is baked, and every baked header in the tree now has to match its source
CONTRACT-P7 §5.1's (A) and (D), and (D) is what makes (A) safe to have.
(A) WireDepthMipmap.{vert,frag,inc}. VK_FORMAT_FEATURE_BLIT_DST is OPTIONAL for depth
formats, so a depth chain through a shader is the ordinary case and not the exotic
one - the monolith arm has carried such a fallback since before the split. The wire
arm had none, so a depth texture the device would not blit died on the first
disjunction of `mipmap-shader-format-or-shape`, and a DEPTH|STENCIL one died a guard
earlier as `depth-stencil-mipmap@P7` whether or not it could be blitted.
The monolith's fallback is not reusable, which is the whole of (A): it builds a GL
ProgramObject, two ShaderObjects and a GL sampler, binds through the uniform manager's
global UBO and writes uSrcTexelSize as a default-block uniform - four frontend objects
and a GL compiler on the server's apply thread. The baked program is the same shader
with the same arithmetic on a push constant and its own descriptor set. The fragment
stage is a PORT and not a rewrite: §3.2 retires a refusal by making the wire arm
observably the monolith's, so the 2x2 box lands where the monolith's lands, including
the half texel its ivec2(texCoord * srcTexelSize) sits off the destination centre.
`depth-stencil-mipmap@P7` therefore splits. DEPTH-only retires into the baked program.
DEPTH|STENCIL declines - MGLOG_E_ONCE and return, before the chain is grown, so a level
this verb will not fill is not created and then recorded as defined. A decline rather
than a Fatal because the monolith does no better: its fallback asserts depth-only, and
an assert is nothing in the release build both arms ship as. Nothing in GL promises a
stencil mip either, and this pass writes gl_FragDepth - it would leave the stencil
aspect of the level it just produced undefined.
(D) MOBILEGL_BAKED_INTERNAL_SHADERS. A baked header is a compiler output committed with
its input beside it and nothing connecting the two: edit the source and the build stays
green while the shader that runs is the one from before the edit. MG_Test's
BakedInternalShadersTest recompiles all eight arrays - WireColorBlit x2,
WireDepthMipmap x2, the iterationRP witness, the three probe stages - from their
committed GLSL with the in-tree glslang and compares word for word.
THE GATE IS THE BAKER. scripts/bake_internal_shaders.py compiles nothing; it runs this
binary with MOBILEGL_BAKE_INTERNAL_SHADERS and splices the words it emits. A gate that
used the glslang LIBRARY while the baker shelled out to a glslangValidator BINARY would
be two compilers with no rule about which is right, and the day their defaults diverge
the gate reds on a header nobody can regenerate.
What the first run measured, which is the one thing nobody could know beforehand:
WireColorBlitSpirv.h and all three arrays of PrimitivesGeneratedNoXfbProbeSpv.h were
already fresh - the hand-run glslangValidator words reproduce exactly. The iterationRP
witness was stale, as its own prose said; it is regenerated here (2142 -> 2143 words),
and the witness magic 0x50323033 is still there because it is a constant in the .comp
rather than a property of the words. All three provenance comments now point at the
script and the gate instead of at a tool on somebody's PATH.
Scenarios, on the three Magma arms: GenerateMipmapDepthWithoutNativeBlitPixels runs
DEPTH_COMPONENT24 and DEPTH_COMPONENT32F under MGITEST_MAGMA_FORCE_SHADER_MIPMAP=1 and
reads level one back through a real sampled attachment, asserting per half and leaving
row 3 - the straddle band - unpinned, because pinning it would assert the half-texel
offset rather than the mip. GenerateMipmapDepthStencilDeclinesAndKeepsTheSession takes
no knob (the decline is on the aspect, before blit support is asked about) and pins that
the session survives and level zero still holds what was cleared into it.
Red once, three of them, executed and reverted:
- a one-character edit to WireDepthMipmap.frag (no rebuild - the gate reads the source
at runtime) reds the WireDepthMipmapFragment row at word 279;
- with the depth arm disabled, the DepthMip entries die with Fatal{UnmigratedVerb,
"Magma:mipmap-shader-format-or-shape format=125 ... aspect=0x2 ...
missing=COLOR_ATTACHMENT"} - format 125 is X8_D24_UNORM_PACK32, which slice 1's
diagnostic names for us;
- with the Fatal restored, the decline case dies as
Fatal{UnmigratedVerb, "Magma:depth-stencil-mipmap@P7"}.
Gates: integration-magma-split 77 (+2), -spawn 56 (+2), -tcp 58 (+2), 0 red;
ctest -L unit 2410 (+8, the gate's rows); informational integration-magma-full-split
513, 0 red, 59 skip (base 510/0/57); fatal_census green (79 abort sites, 43 words, 0
unmarked); link_ratchet --assert-monotone unchanged at 186, p7-magma 101.
G1 holds and it was not obvious: the witness header is compiled into the pull build
too, and its word count changed. Pull .text is still 0xa52203 and the defined-symbol
name list is identical to ~/w7/p7-before/pull-syms.txt line for line (30570) - the
change lands in .rodata and widens no instruction encoding.
VulkanRenderer.h is edited outside this package's file list: the new pass needs four
private declarations next to the colour blit's. Flagged for the integrator.
|
||
|
|
df17c416c0 |
[MobileGL, MG_Backend, MG_Remote, scripts] (P7): the split wire comes up before the first frontend object, and the caps mirror stops deciding a family's fate from a placeholder
F1. `MG_State::Init()` runs before `MG_Backend::Init()`, and the second is what
starts the session - so `GLContext`'s `TextureState` constructor materialised its
eleven default texture objects, each of them emitted `resource_create` through
`FamilyIsLive`, and `CapsMirror::ServerConsumes(0x400)` answered every one of them
from a generation-0 placeholder with `callMask=0`. All eleven records were dropped
and the whole event was one WARN line:
MG_Remote client: the server does not consume MGPipe subsystem 0x400 - this
family emits NOTHING and the legacy pull path runs for it (R-8). callMask=0x0,
caps generation 0
It is NOT a race. The line reproduces byte-for-byte on lavapipe and on the Adreno
830, because the two Init calls are two statements on one thread. And "the legacy
pull path runs for it" is false on the client under split: there is no pull path
on this side of the wire, so withholding is not a fallback, it is a drop that only
a later respecify's self-healing create ever undoes.
Two of the three options the brief offered do not apply, and both facts are worth
recording. (b) "extend the P6.5 fix to inproc" is already the tree: `FinishStartup`
step 7 is the one funnel every transport reaches and it will not return without a
real snapshot. (a) "a bounded wait in Consumes()" cannot work alone and would
deadlock: at `MG_State::Init()` no handshake is in flight, and the one that will
land is started later BY THE SAME THREAD.
So the fix is the ORDER, with the rule behind it as the gate:
* `MobileGL::Initialize` calls `MG_Backend::InitSplitRolesBeforeState()` before
`MG_State::Init()`. `Init()`'s split arm becomes one body, `InitSplitBackend()`,
shared with the direct callers that still reach `Init()`; the monolith arm keeps
its place after `MG_State::Init()`, because moving it would move pull `.text`.
* `CapsMirror::ServerConsumes()` refuses to answer from a placeholder. It waits,
bounded, when a bring-up is genuinely in flight on ANOTHER thread, and otherwise
dies as `Fatal{CapsBeforeFirstSnapshot, "<family>"}` through `SessionFail` -
a new family word, one row in `FatalFamilies.def`, no new abort site.
* Two arms are exempt and say why in place: the server arm (`MGPipeServerArm()` -
the apply thread and the spawn server, where the client's mirror is the wrong
object rather than a late one), and a process whose own configuration never
asked for a split transport (`MG_Config::SplitTransportRequestedByConfig`, set
by `MG_ConfigLoader::InitTransport`, which is what tells a real run apart from a
fixture that assigns `MG_Config::Transport` by hand).
The read accessors keep P5's ruling untouched: `LogBackendInfo` reads
`GetRendererInfo()` during `MG_Backend::Init()` and an abort there is a process that
cannot start. Only the DECISION changed. The warning was not made quieter and the
callMask was not defaulted to all-ones.
`MOBILEGL_TEST_DELAY_FIRST_CAPS_MS` (server side, disaggregated builds, inert unless
set) holds back the FIRST CapsSnapshot. On spawn/tcp that is a genuinely late
snapshot in another process and it exercises the client's step-7 wait; on inproc it
only makes `Start` slower, which is itself the proof that the only window a client
can read a placeholder in is the one before `Start` is called.
G1: `.text` 0xa52203 and the 30570-symbol list identical to p7-before/pull-syms.txt.
Census: 79 abort sites unchanged, 44 family words (was 43). Link ratchet: 186,
unchanged.
|
||
|
|
801f8edaa6 |
[scripts] (P7): the parity self-test patches the seam the Magma tiers read through
Package D added a test that patches lane_cases and hands spawn_lane_parity.py a placeholder build dir; package L then made the three Magma tiers read through a new lane_names, so the placeholder reached a real ctest and the unit label went red on the integrated tree. Patching lane_names to an empty set on every arm makes those tiers report "nothing to compare" and leaves the assertion about lane_cases intact. |
||
|
|
8bb6309a1c |
[scripts, CI, docs] (P7): the 184-symbol link-closure ratchet lands as a gate
CONTRACT-P6.md 12.1 has carried "a ratchet recomputes the 184 in CI and asserts it only
ever falls" as an obligation since P6. The roadmap handed it to P6.5; the P6.5 line never
received it, and scripts/ci/ has never had anything that computes this number. ID-P7-7
gives it to P7 wave 0. This is it.
scripts/link_ratchet.py mechanises a6's hand experiment: partition the per-object output
of the single MobileGL target into SERVER / FRONTEND / SHARED, then compute
(SERVER undefined) - (SERVER defined) - (SHARED defined) intersect (FRONTEND defined),
which is the undefined-symbol list a real link of a server-only image would print. The
partition is an explicit table with a rationale per row, because it IS the module boundary
the build system does not have (SOURCE_FILES is one flat list; boundaries are P13's work).
An object matching no row is a hard failure, as is a build whose CMakeCache lacks the three
disaggregated options, or an empty role set - every way this gate could go green without
having measured anything is an explicit exit 2.
Measured on
|
||
|
|
1de8f02ebe |
[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.
|
||
|
|
3d9a38a979 |
[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.
|
||
|
|
484a56a5ae |
[scripts, MG_Pipe, MG_Backend, MG_Test] (P7): the census docstring's triage follows what the same wave retired, and the comments stop joining the @P7 census
Two corrections to the two commits before this one. The widening's docstring was written against the 83 sites it found, and the commit that routed five of them through Session::Fail did not revisit the prose. It now describes the 79-site floor the baseline actually records, says which five went and where, and states that the enforceable artefact is the baseline's per-file map rather than the counts in the prose - so a reader who finds the two disagreeing knows which one to believe. The three buckets are restated too: `(ii)` is no longer "owned by a Ph / P7 row", because with the Magma wire arms routed what is left there is the peer-reachable deaths in the applier and the two backends, which is exactly the set ID-P7-1 scopes to Ph's fuzz arm 2 AFTER P7. And the routing commit's own comments spelled the at-sign refusal marker while explaining what routes through them, which put SEVEN comment lines into the retirement census: `grep @P7` went from 15 sites in 4 files to 22 in 6, and that grep is how wave 2 will measure which refusals it has retired. The prose says the word instead, and the count is 15/4 again. |
||
|
|
a5dcbb444f |
[MG_Remote, scripts, MG_IntegrationTest] (P7): the supervisor names a faulted session, and the smoke that proves it is finally a ctest entry
Ph slice (1) (ID-P7-1). Three `::waitpid(active, nullptr, WNOHANG)` calls in the `--serve` loop threw the status away, so a session child that died of SIGABRT inside SessionFail and one that returned from its control loop and _exit(0)'d were the SAME EVENT to the supervisor: `active = -1`, no line, nothing to count. ID-P7-1 declines the literal 98-site latch translation because P6.5's fork-per-session already delivers "the next connection is served as usual"; what was missing is that anyone could TELL a faulted session from a finished one, which is what an operator, a fuzz arm and a flake triage all actually need. One `ReapActiveSession()` where there were three call sites, asking WIFEXITED / WIFSIGNALED / WTERMSIG - the same three questions ServerSpawn.cpp:289 asks of the same kind of child - and logging `pid=<n> reaped exit=<c>` or `signal=<n>` with the supervisor's lifetime `sessionsFaulted` beside it. A refused handshake exits 0 and is NOT a fault, which is right: protocol.fbs:86 says a rejection is a normal session outcome. The running total is on every reap line as well as on the summary, because the fixtures end a supervisor with SIGTERM and a figure only printed at a chosen exit would never be seen. THE IDENTIFIER ROW'S PREMISE IS WRONG, MEASURED. The plan asks for CtrlEnvelopeBufferHasIdentifier at ServerMain.cpp:193 because ServerSession::ParseEnvelope asks it and this loop did not - but the generated VerifyCtrlEnvelopeBuffer already IS `VerifyBuffer<CtrlEnvelope>(CtrlEnvelopeIdentifier())` (protocol_generated.h:2378), so a wrong identifier was refused here and ParseEnvelope's second call is redundant too. Recorded for the integrator. What was real is that both refusals were SILENT: a peer whose post-Welcome frame was garbage had its session ended with no line in the log, and a fuzz arm that cannot tell "refused, by name" from "the child went away" measures nothing. So the identifier is now asked first - it is the specific diagnosis where the verifier's is the general one - with the length guard that asking it first requires, and both say so. scripts/ci/tcp_supervisor_smoke.py has been in the tree since P6.5 asserting four supervisor controls and was referenced by NOTHING - no ctest entry, no workflow step - so nobody could have said whether those four were green. It is now `TcpLane.SupervisorProtocolControls` beside the TCP lane's own fixtures, labelled integration-tcp, under the lane's resource lock (a second supervisor's child would answer the other's peers with Busy). It needs flatc, which is deliberately not in the build graph, so it resolves one gen_protocol.py's way and exits 77 - ctest SKIP - when there is none, rather than passing on a run that did not happen. Two cases added to it: a session child killed with SIGABRT must be named by pid and `signal=6` with `sessionsFaulted` one higher than before, and the next Hello must still be welcomed; and a steady-state frame carrying the wrong file identifier must be named rather than silently dropped. Red-once, both ways, against the real image: making the reap discard the status again reds with "the supervisor did not name session pid=N as killed by signal=6", and deleting the identifier branch reds with "read a frame with the wrong file identifier without saying so". |
||
|
|
e1ec69341a |
[MG_Pipe, MG_Backend, MG_Remote, MG_Test, scripts] (P7): the Magma wire fatals and the two Staged aborts go through Session::Fail
Five deaths in the split server image raised their own std::abort(). Three of them are funnels - MagmaWireFatal (Renderer/WireFramebuffer.inc), WireDescriptorFatal (Renderer/UniformManager.cpp) and WireBufferLegacyFatal (Renderer/WireDraw.inc) - and the fifteen `@P7` refusals on the tree (8 in UniformManager.cpp, 4 in WireFramebuffer.inc, 2 in WireDraw.inc, 1 in VulkanRenderer.cpp; plan section 1.3's count confirmed) all die through two of them. Every one of those deaths published NO SessionFault frame, so the peer read a bare EOF; bumped NO SessionFaultCount(), so exit gate S8 could neither confirm nor falsify it; and carried a hand-typed family word with no path to FatalFamilies.def's projection. MG_Backend may not name an MG_Remote symbol on its own account, so the route is a seam in MG_Pipe with MGP_TRIP_WIRE_REPORT's shape (PipeApply.cpp:66, and the new code sits beside it): MG_Pipe/PipeSessionFail.h declares MGPipeSessionFail, PipeApply.cpp defines it inside `#if MOBILEGL_BUILD_DISAGGREGATED`, the DEFAULT behaviour is byte-identical to what the three funnels did on their own, and MG_Remote::InstallPipeSessionFailHook() points it at SessionFail. The install is in InitServerRoleCommon (MG_Backend/Init.cpp), step 0, because that is the one function BOTH server roles run - the inproc role and the spawn/TCP session child - so there is no per-transport install to get wrong. MGPipeFatalFamily is a two-value boundary enum, NOT MGFatalFamily cast to an integer: the .def's enumerators are positional and a row inserted in its middle would silently re-point every hook call at a different family. FatalFunnel.cpp's adapter is the one place the two vocabularies meet, as a switch with a named default. The family word stays UnmigratedVerb rather than becoming a new MagmaWireRefusal. Three reasons: the message strings are required to stay byte-identical (5.2), and the retrace refusal censuses recorded since P5b count these deaths by that word - a rename invalidates every `@P7` measurement taken against them; `Magma:` in the detail already separates the Magma arm from the GLES UnmigratedVerb deaths, so a new word adds no discrimination a grep does not have; and its wire projection would be ProtocolCorruption, exactly UnmigratedVerb's. Recorded for the integrator. Ph slice (2) in the same commit: Server/StagedShadow.h's RequireCovered and Server/StagedTextureStore.h's RequireLevelBytes were MGLOG_F + bare abort. Both are inside MG_Remote already, so they call SessionFail directly, message verbatim; check_include_closure.py's four probes do not reach either header and the gate is green. Census: 83 abort sites -> 79 over 20 files (five sites retired, one gained for the seam's no-hook default, which is argued into FUNNEL_SITES), baseline rewritten in this commit - the downward ratchet's notice is what asked for it. Two gate bugs the widening exposed and this commit fixes: the SessionFail call regex also matched `MGPipeSessionFail(` (a lookbehind now), and a funnel's anchor needed a wider window than a marker's (kFunnelAnchorWindow). Red-once, three ways. Pointing MagmaWireFatal back at its own abort reds the census naming WireFramebuffer.inc 0 -> 1. Making the seam skip the hook reds both new death cases - `TheMagmaWireVerbDeathReachesSessionFailAndBumpsTheFaultCount` on the exit code, because it reads SessionFaultCount() out of a SIGABRT handler and gets 0 instead of 1, and `TheSeamHandsTheInstalledHookItsFamilyAndItsLineVerbatim` on the line the hook echoed. |
||
|
|
f141918aa1 |
[scripts, MG_Remote, MG_Impl, MG_Test] (P7): the fatal census gate widened to the split server image
`scripts/ci/fatal_census.py` scanned `MG_Remote/` and saw four abort sites. CONTRACT-P6
§12.1 already says what the server image is - "P6's server image is the whole
libMobileGL.so" - and the server process was executing seventy-nine more deaths the gate
could not see: 15 in DirectGLES.cpp, 12 in Managers.cpp, 11 in VkBufferManager.cpp, 7 in
PipeRoute.cpp. SCAN_ROOTS is now MG_Remote / MG_Pipe / MG_Backend / MG_Impl/Pipe /
MG_State, `.inc` joins `.cpp`/`.h` (the Magma wire arms and the generated wire records are
.inc files, and 20 sites are reachable only through one), and MG_Benchmark /
MG_IntegrationTest join MG_Test in the exclusion.
Four rules now, where there were two:
1. an abort names its family within twelve lines, OR it is argued into FUNNEL_FILES /
the new FUNNEL_SITES table. FUNNEL_SITES exempts an individual funnel inside a file
that has ordinary named deaths around it, and only when one of the file's anchors
appears in the same window - so the exemption follows the funnel if it moves, expires
if it is deleted, and does not cover an unrelated abort added to the same file. Two
entries, one line of reason each: PipeApply.cpp's MGP_TRIP_WIRE_REPORT and
PipeWire.inc's MGPipeWireProtocolFatal.
2. unchanged: a WireLogFatal / SessionFail call carries a `Fatal{` in its string.
3. NEW: every family word found in the perimeter has a row in FatalFamilies.def. Eleven
words did not, and now do (see below).
4. NEW: every `Refuse{Word}` names a RefuseCode enumerator. This is what catches
`Refuse{AuthenticationRequired}` (SocketTransport.cpp:161), a word protocol.fbs has
never had - PH-7 (2). Renamed to the enum's own `Authentication`, and
SocketTransportTest pins the spelling to `EnumNameRefuseCode` so the two cannot
drift again.
`abort_sites` was recorded and never compared. It is now a DOWNWARD ratchet with a
per-file map beside it, so "83 became 84" reports as "VkBufferManager.cpp went 11 -> 12,
here are its lines"; fewer sites - the direction `@P7` retirement moves the number - asks
for a re-baseline rather than blocking one.
Eleven new `.def` rows for the eleven rowless words. Ten are ProtocolCorruption for the
reason that bucket already states. ResourceUnavailable is ServerCrashed, not SegmentMismatch:
SegmentMismatch means a shared SEGMENT was the wrong size, and telling a peer that when a
VkBuffer allocation failed would be a lie about whose geometry was wrong. A twelfth word was
collapsed rather than given a row - `InitialBytesNotCarried` (PipeFill.cpp) said the same
thing as `UncarriedInitialBytes` (WireTables.cpp) about the same record, and two words for
one family is the drift a6 censused.
Red-once, four ways: an unnamed `std::abort()` appended under MG_State reds naming the file
and the line; deleting the `Fatal{` from PipeRoute.cpp's ResidualBlockSize reds; putting
`Refuse{AuthenticationRequired}` back reds rule 4; a typo'd family word reds rule 3 and the
vocabulary ratchet together.
|
||
|
|
3ba150d021 |
[tools, android-plugin, CI] (P7): the device matrix runner selects DirectVulkan, repeats are archived, and the spawn env parse is entry-aware
wave 0 item 5. Three instruments P7's device window needs, and the CI steps that
can make each of them red.
run_tcp_matrix.py --backend DirectVulkan end to end. --backend already existed and
already filtered by each case's ci_backends; what did not exist is a per-backend
GOLDEN. The two backends shared `golden` plus an optional `alternate_golden`, and
alternate_golden is an OR across backends, not a per-backend key - so a
DirectVulkan run that matched the DirectGLES picture passed, which is the "went
green on the wrong arm" shape the exit gate exists to catch. trace_cases.json
gains `backend_overrides.<backend>` ({golden, alternate_golden, ssim_threshold}
only: restating target_call or a crop would stop the two backends retracing the
same frame through the same window). A per-backend golden REPLACES the shared
pair, matching another backend's declared image is refused BY NAME, and a --case
named explicitly that does not run a requested backend is an error instead of one
plan fewer and no message. The CMake emitter and the APK matrix refuse a case that
declares the key rather than silently emitting one golden for both arms.
DirectGLES is unchanged and that is asserted, not asserted-in-prose: a case with no
override resolves to itself, and the key is dropped from the resolved case even for
the backend that overrides nothing - so giving DirectVulkan its own golden does not
move the DirectGLES identity fingerprint and does not invalidate its checkpoints.
Each results.json row now records the golden, alternate golden and threshold it was
scored against.
run_android_retrace_local.py gets --matrix (the CI split subset, 39 cases, each
running only its own ci_backends - not --all, which adds the rd12 workload ID-P7-4
excludes), --repeat N, and --archive-dir. The archive is the point: the result root
is keyed by case and backend and by NOTHING else, so repeat 2 overwrites repeat 1
and the only artefact that survives a three-repeat run is the last one, which makes
"were the three repeats the same picture?" unanswerable after the fact - in the one
place where re-running to find out is expensive. It also refuses --benchmark with a
non-monolith --transport, which has always produced a monolith run under a spawn
label (run_benchmark_case passes args.env alone; p6/README.md records the pitfall).
compare_actuals.py computes the pair result.json cannot: SSIM between two actual
PNGs, plus a case x repeat x ssim-vs-golden x ssim-vs-first-repeat table over an
archive. It is the retrace gate's OWN SSIM - a transcription of ComputeChannelSsim
/ ComputeRgbSsim (trace_replay_core.cpp:630/:671), the only SSIM in the tree - and
the crop comes from each repeat's own result.json, so the two columns describe the
same rectangle. PNG decode is stdlib zlib, because an unavailable Pillow in the
device window would turn "the repeats diverged" into "the tool did not run".
TraceReplayActivity: resolveSpawnServerPath's two decisions were String.contains()
on the whole joined K=V;K=V list and neither was entry-aware. The one that bit:
`--env MOBILEGL_IPC_SERVER_PATH` with no '=' is the documented UNSET spelling
(trace_env_overrides_test.cpp:92) and the only way to ask for "spawn with no image"
and watch LaunchServer refuse by name - it did not match "MOBILEGL_IPC_SERVER_PATH="
so a resolved path was appended AFTER it and, because ApplyEnvOverrides applies in
order with setenv(...,1), the deliberate unset was silently undone. That is exactly
the "silently replacing it would make that knob untestable" the method's own comment
forbids. Two more: the key inside another entry's VALUE flipped both decisions the
wrong way, and the transport match was case-sensitive while ConfigLoader lower-cases
the value before matching (ConfigLoader.cpp:322). The parse moves to
SpawnServerPath, a class with no android.* import, so test_android_lifecycle.py
compiles and runs it with plain javac - the parse had no host-side coverage at all,
and its on-device failure mode is "the knob had no effect".
Only spawn gets a path, deliberately: it is the only transport that execs an image.
Red-once, all four: a stub case whose result names the DirectGLES golden fails a
--backend DirectVulkan run with "matched a golden another backend declares"; a
synthetic PNG pair with a closed-form SSIM (identical = 1.0 exactly, constant
black vs white = C1/(255^2+C1), inverted halves = (C2-2v)/(2v+C2)); the pre-fix
resolveSpawnServerPath body fails eight of SpawnServerPathTest's checks; and the
DirectVulkan TCP proof battery is the DirectGLES one under the other prefix,
because an empty prefix selection raises nothing and reads as a clean pass.
CI: test_run_tcp_matrix.py and test_compare_actuals.py join the R-16 step. The
matrix driver's stub regressions had NO CI step - they were run by hand and
recorded in a note - and they guard the tool that decides whether a device golden
run passed.
Counts in WSL: test_run_tcp_matrix 12 -> 18, tcp_lane_tools 4 -> 6,
test_compare_actuals 12 new, test_android_lifecycle green with the new Java unit.
|
||
|
|
fe28bdb5f3 | [MG_Remote, MG_Pipe, MG_Test, CI, tools, docs] (P6.5): the first wave completed and reviewed - archive v2, publication boundary, half-close, AcceptPair/role fixes, device re-validation | ||
|
|
018fab0f5b | [WIP] (MG_Remote): implement P6.5 TCP and stream transport | ||
|
|
242fd45cd7 | [Fix] (CI): read role logs and retry device disconnects | ||
|
|
9043442454 |
[MG_Test, CI] (P6): the last two readers the role split left behind
build-linux-verify could not compile PipeStatsTest: RoleDerivedJsonDumpPathForTesting is DISAGGREGATED-only and the verify flavour is deliberately monolith. The case name stays registered and GTEST_SKIPs there, matching the PIPE_PUSH pattern, so ctest -N still matches between flavours. runtime_mode_proof.py logs opened MOBILEGL_LOG_FILE_PATH as a file. After the split that name is a base and the sink writes <base>.client.log / <base>.server.log, so the inproc proof died on FileNotFoundError after a green lane. It now reads through split_log_paths' role helpers and names the paths it looked for when none exist. |
||
|
|
94c130d639 |
[MG_Util, MG_IntegrationTest, CI] (P6): the readers the role split left behind
The per-role log split renamed BOTH halves so that an un-updated reader would fail loudly instead of silently reading half a session. It worked: CI found four readers this way. This is them. - MG_Util/Debug/Log.h: the role vocabulary now exists in the PULL build too, header-only. It was wholly inside #if MOBILEGL_BUILD_DISAGGREGATED, so PipeInputsTest - which builds in the verify flavour - could not name ReadRoleLogs and took the whole build-linux-verify job down at compile time. Inline rather than out-of-line because of G1: nothing in the library calls these, so an inline definition emits code into the readers and NOTHING into libMobileGL.so. Verified: pull symbols 30570 -> 30570, 0 added / 0 removed, .text still 0xa52203, and zero role-log symbols in the pull library. - PipeStatsWindow.h: the harness copy of the naming rule is now flavour-aware. It derived `.client` in BOTH flavours, so in the verify build - one role, MOBILEGL_LOG_FILE_PATH written unchanged - it opened a file that never existed. The copy has to stay a copy: MG_Util's RoleLogPath is `t` (local) in the shipping .so this module links, so calling it does not link. Added LogMark/MarkLaneLog/ReadLaneLogSince: one offset PER ROLE, because a single scalar over the concatenation slides by whatever the other role wrote. - The four arming scenarios: they asserted on lines the BACKEND emits, and under inproc the backend runs on the apply thread - the server role - so the line lands in the server's log. Reading only the client's half reported the emulation unarmed, i.e. accused the product of a defect the reader invented. Four copies of the same private helper pair now delegate to the harness. - scripts/ci/magma_runahead_checks.py: it unlinked and read the base name as if it were a file, so the negative arm saw an empty log and could not prove the knob took. It now imports split_log_paths' derivation - the authoritative one - rather than becoming a third copy. Local verification (WSL, lk-split + c6-pull): - the 4 CI-red entries: 10/10 PASS under inproc, 10/10 under monolith - unit role-log readers: 510/510 PASS - magma_runahead_checks negative: run_ahead_0 EXPECTED_RED, restored GREEN - the 5 affected TUs compile clean with MOBILEGL_BUILD_DISAGGREGATED=0 - G1: 0/0/0/0, .text 0xa52203 Red-once is the CI run itself (35677991453), which failed for each of these reasons before the change. |