From 9032561722b08fae4b57e001072499d1ba30d875 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 17 Oct 2026 23:37:24 -0400 Subject: [PATCH] [Refactor, Test] (docs/ci, docs/Disaggregated, MG_Backend/MGPipe, MG_Remote/Client, MG_Remote/Transport, MG_Test/Wire, MobileGL, scripts/data, tools/trace_replay): delete the MOBILEGL_IPC_VERB_BARRIER knob - retires RemoteRunAhead.ClearingTheVerbBarrierDisarmsRunAheadEvenWithTheCapBit --- MobileGL/Config.h | 10 +---- MobileGL/ConfigLoader.cpp | 15 ++----- MobileGL/MG_Backend/MGPipe/PipeInputs.h | 4 +- MobileGL/MG_Remote/Client/ClientSession.cpp | 43 +++---------------- MobileGL/MG_Remote/Client/ClientSession.h | 18 +++----- MobileGL/MG_Remote/Transport/SessionRings.h | 5 +-- .../MG_Test/Wire/InitialCapsStartupTest.cpp | 1 - .../MG_Test/Wire/RemoteClientE1Controls.inc | 7 +-- MobileGL/MG_Test/Wire/RemoteClientTest.cpp | 23 ---------- MobileGL/MG_Test/Wire/SessionTest.cpp | 5 +-- .../Wire/StreamClientPublicationTest.cpp | 1 - .../design/09-build-switches-counters.md | 1 - docs/Disaggregated/design/10-phase-shapes.md | 2 +- docs/ci/ci-cleanup-log.md | 1 + scripts/data/skip_census_baseline.json | 1 - tools/trace_replay/README.md | 10 ++--- tools/trace_replay/benchmark_tcp_credits.py | 2 +- tools/trace_replay/measure_loopback_cpu.py | 2 +- tools/trace_replay/measure_tcp_stage_burst.py | 2 +- tools/trace_replay/measure_transport_cpu.py | 2 +- tools/trace_replay/run_tcp_matrix.py | 5 +-- tools/trace_replay/test_run_tcp_matrix.py | 10 ++--- tools/trace_replay/test_run_trace_case.py | 2 +- 23 files changed, 42 insertions(+), 130 deletions(-) diff --git a/MobileGL/Config.h b/MobileGL/Config.h index 772bb5ed..585834d1 100644 --- a/MobileGL/Config.h +++ b/MobileGL/Config.h @@ -696,12 +696,6 @@ namespace MobileGL::MG_Config { // platform and the backend's POST self-test allow it; 0 = never grant it (the session // runs T2 and says so). Read by the server role only; kept through ServerSpawn. Uint32 AllowAdoptT0 = 1; - // MOBILEGL_IPC_VERB_BARRIER: 1 = the client blocks at every verb boundary until - // appliedSeq reaches its emitSeq (R-1). 0 is the negative control: it is EXPECTED to - // be red, because 31 of the 63 PipeInputs fields are still pulled from a live - // GLContext by the client's residual fill and a free-running queue lets the server - // read a FUTURE value of them. - Uint32 VerbBarrier = 1; // MOBILEGL_IPC_RUN_AHEAD (P5e, docs/archive/contracts/CONTRACT-P5E.md §1): 1 = after publishing an // UNBARRIERED record the client returns immediately instead of waiting for its apply. // It is one half of a conjunction and never a switch on its own - the client arms @@ -712,9 +706,7 @@ namespace MobileGL::MG_Config { // 0 IS THE A/B CONTROL AND NOT A NEGATIVE ONE: the server code, the fill decision and // every record are identical on both arms, and the only difference is whether the // client waits. That is what makes "is the picture the same" a question about the wait - // rule alone. MOBILEGL_IPC_VERB_BARRIER=0 keeps its own meaning and stays the - // lockstep arm's negative control; under run-ahead it is the one that must go red, at - // the first barriered row's stale pull. + // rule alone. // // Forced to 0 by MOBILEGL_PIPE_VERIFY, beside BatchWaits: the comparator needs a // client-filled gPipeInputs block for every verb, and run-ahead is precisely the diff --git a/MobileGL/ConfigLoader.cpp b/MobileGL/ConfigLoader.cpp index 3a03a2a7..b8387cb9 100644 --- a/MobileGL/ConfigLoader.cpp +++ b/MobileGL/ConfigLoader.cpp @@ -609,7 +609,6 @@ namespace MobileGL::MG_ConfigLoader { ipc.AdoptTier = QueryEnvUint32("MOBILEGL_IPC_ADOPT_TIER", MG_Config::kAdoptTierUnset, 0, 2); // P11 B2: the server's own T0 allow switch (Config.h). ipc.AllowAdoptT0 = QueryEnvUint32("MOBILEGL_IPC_ALLOW_ADOPT_T0", 1, 0, 1); - ipc.VerbBarrier = QueryEnvUint32("MOBILEGL_IPC_VERB_BARRIER", 1, 0, 1); // P5e (docs/archive/contracts/CONTRACT-P5E.md §1). The wait rule's A/B, parsed here like every // other IPC knob and armed only where the server publishes kCapRunAheadApply. ipc.RunAhead = QueryEnvUint32("MOBILEGL_IPC_RUN_AHEAD", 1, 0, 1); @@ -716,7 +715,7 @@ namespace MobileGL::MG_ConfigLoader { // log that does not name it makes every run ambiguous about its own configuration. MGLOG_I("Config: IPC ring=%uMiB stage=%uMiB wire-deferred=%uMiB spin=%uus event-wait=%ums " "persistent-block=%uKiB create-window=%u pbo-readback-sync=%u poll-escalate=%u " - "adopt-tier=%s allow-t0=%u verb-barrier=%u run-ahead=%u present-credit=%u control-timeout=%ums " + "adopt-tier=%s allow-t0=%u run-ahead=%u present-credit=%u control-timeout=%ums " "cold-start=%ums strict=%d audit=%d role-split-state=%d affinity='%s' surface=%s", ipc.RingMb, ipc.StageMb, MG_Config::RecordArm.WireDeferredMb, ipc.SpinUs, ipc.EventWaitMs, MG_Config::RecordArm.PersistentBlockKb, ipc.CreateWindow, ipc.PboReadbackSync, ipc.PollEscalate, @@ -724,15 +723,9 @@ namespace MobileGL::MG_ConfigLoader { : ipc.AdoptTier == 1 ? "1" : ipc.AdoptTier == 2 ? "2" : "unset(T0)", - ipc.AllowAdoptT0, ipc.VerbBarrier, ipc.RunAhead, ipc.PresentCredit, ipc.ControlTimeoutMs, - ipc.ColdStartMs, static_cast(ipc.StrictErrors), static_cast(ipc.Audit), - static_cast(ipc.RoleSplitState), ipc.ServerAffinity.c_str(), - MG_Config::ServerOwnedWindowSurfaces() ? "server" : "offscreen"); - if (ipc.VerbBarrier == 0) { - MGLOG_W("Config: MOBILEGL_IPC_VERB_BARRIER=0 is the R-1 NEGATIVE CONTROL and is " - "expected to fail: the client still pulls 31 of 63 PipeInputs fields from a " - "live GLContext, so an unbarriered queue lets the server read future values"); - } + ipc.AllowAdoptT0, ipc.RunAhead, ipc.PresentCredit, ipc.ControlTimeoutMs, ipc.ColdStartMs, + static_cast(ipc.StrictErrors), static_cast(ipc.Audit), static_cast(ipc.RoleSplitState), + ipc.ServerAffinity.c_str(), MG_Config::ServerOwnedWindowSurfaces() ? "server" : "offscreen"); } #endif diff --git a/MobileGL/MG_Backend/MGPipe/PipeInputs.h b/MobileGL/MG_Backend/MGPipe/PipeInputs.h index b556b857..d7c9ef39 100644 --- a/MobileGL/MG_Backend/MGPipe/PipeInputs.h +++ b/MobileGL/MG_Backend/MGPipe/PipeInputs.h @@ -965,9 +965,7 @@ namespace MobileGL::MG_Pipe { // PLAIN, NOT ATOMIC, AND THAT IS THE SAME RULING TABLE 3 MAKES FOR gPipeInputS ITSELF // (CONTRACT-P5.md section 4): the verb barrier leaves at most one of {GL thread, apply // thread} runnable, so there is one writer at any instant. This counter, m_serverStampedVerb - // and FilledGen[] all rest on that and on nothing else - so MOBILEGL_IPC_VERB_BARRIER=0, - // R-1's negative control, is a data race on all three as well as the correctness failure it - // is there to show. It is expected to be red; it is not expected to be meaningful. + // and FilledGen[] all rest on that and on nothing else. Uint64 MGPipeResidualPullCount(); void MGPipeResetResidualPullCountForTesting(); diff --git a/MobileGL/MG_Remote/Client/ClientSession.cpp b/MobileGL/MG_Remote/Client/ClientSession.cpp index 9f86f6fb..fc4cad66 100644 --- a/MobileGL/MG_Remote/Client/ClientSession.cpp +++ b/MobileGL/MG_Remote/Client/ClientSession.cpp @@ -236,14 +236,6 @@ namespace MobileGL::MG_Remote::Client { #endif } - Bool VerbBarrierFromConfig() { -#if MOBILEGL_BUILD_DISAGGREGATED - return MG_Config::Ipc.VerbBarrier != 0; -#else - return true; -#endif - } - // ---- c1: the barrier's two flags ------------------------------------------------ // // thread_local for the client's own "am I waiting", a shared atomic for "is the apply @@ -1810,14 +1802,6 @@ namespace MobileGL::MG_Remote::Client { return MOBILEGL_ERR_INVALID_ARGUMENT; } - m_barrierArmed = VerbBarrierFromConfig(); - if (!m_barrierArmed) { - MGLOG_W("MG_Remote client: MOBILEGL_IPC_VERB_BARRIER=0 - this is R-1's NEGATIVE " - "CONTROL and is EXPECTED to be red. 31 of the 63 PipeInputs fields are still " - "pulled from a live GLContext by the client's residual fill, so a free-running " - "queue lets the server read a FUTURE value of them"); - } - // ---- 6. the client's segment table. IT MUST NOT INSTALL THE PROCESS RESOLVER: there is // exactly one gMGPipeSegmentResolver per process, the SERVER role owns it (table 3), and // the client never resolves a span at all - it only ever writes Ptr = nullptr (R-2's @@ -1989,9 +1973,8 @@ namespace MobileGL::MG_Remote::Client { // permits submittedSeq to be published lazily and RingProducer::Publish encourages batching // the publish, so the shared watermark is allowed to lag the emitter - and a drain // that waited for `appliedSeq >= submittedSeq` would then under-wait and free an - // emitter-owned var-tail while a record still names it. With the verb barrier armed - // the two are equal; under MOBILEGL_IPC_VERB_BARRIER=0, R-1's negative control that - // the phase has to run once, they are not. + // emitter-owned var-tail while a record still names it. Run-ahead and the batched + // waits return before the apply, so the two may differ when Stop() runs. const Uint64 submitted = m_producer.LastPublishedSeq(); m_producer.PublishAndNotify(submitted); if (submitted != 0 && @@ -2338,14 +2321,6 @@ namespace MobileGL::MG_Remote::Client { } } - if (!m_barrierArmed && !ownsReplySlot) { - // R-1's NEGATIVE CONTROL ARM, and the only thing it turns off is the barrier. A - // reply-slot row still waits: the answer is not derivable here and R-5 forbids - // inventing one, so MOBILEGL_IPC_VERB_BARRIER=0 makes the queue free-running, not - // the client clairvoyant. - return seq; - } - ++m_recordWaits; if (MG_Config::Ipc.WaitStats && RunAheadArmed()) ++g_waitCensus.recordWaits[static_cast(op)]; const BarrierWaitScope waiting; @@ -2441,10 +2416,6 @@ namespace MobileGL::MG_Remote::Client { return seq; } - Bool ClientSession::BarrierArmed() const { - return m_barrierArmed; - } - // ---- P5e (ra): the run-ahead latch and the waits it leaves behind --------------------- Bool ClientSession::RunAheadArmed() const { @@ -2465,8 +2436,8 @@ namespace MobileGL::MG_Remote::Client { #if MOBILEGL_BUILD_DISAGGREGATED // THE CONJUNCTION, IN THE CONTRACT'S OWN ORDER (§1). The caps read is last because it // is the only one that costs a mirror load, and because it is the only one whose answer - // can change: the other two are process configuration. - const Bool armed = m_barrierArmed && MG_Config::Ipc.RunAhead != 0 && Caps().HasCap(MG_Pipe::kCapRunAheadApply); + // can change: the other one is process configuration. + const Bool armed = MG_Config::Ipc.RunAhead != 0 && Caps().HasCap(MG_Pipe::kCapRunAheadApply); if (!m_runAheadLatched) { m_runAheadLatched = true; m_runAheadArmed = armed; @@ -2475,7 +2446,7 @@ namespace MobileGL::MG_Remote::Client { "kCapRunAheadApply, so an unbarriered record is published and not " "waited for (CONTRACT-P5E §2.3), paced by a present credit of %u", MG_Config::Ipc.PresentCredit); - } else if (MG_Config::Ipc.RunAhead != 0 && m_barrierArmed) { + } else if (MG_Config::Ipc.RunAhead != 0) { // THE KNOB IS NOT A SWITCH ON ITS OWN, and an operator who set it has to be // told that, or an A/B arm that measured nothing looks like an A/B arm that // measured no difference (Config.h's own argument for parsing it everywhere). @@ -2747,10 +2718,6 @@ namespace MobileGL::MG_Remote::Client { if (MG_Config::Ipc.BatchWaits != 0) return; if (Server::ServerLoop::OnApplyThread()) return; // the applier owns the block inside a verb if (!ClientSessionInstance().Started()) return; // the bring-up window pre-dates the roles - // MOBILEGL_IPC_VERB_BARRIER=0 is R-1's NEGATIVE CONTROL: the single-writer rule is off - // by the operator's own hand there, and EmitAndWait's Fatal{BarrierViolation} owns the - // red. Firing here instead would pre-empt the control's evidence line. - if (!ClientSessionInstance().BarrierArmed()) return; if (!ApplyThreadIsInsideApplier()) return; // LAST, because it is the only thread_local left in the chain: an emutls call per // access in a shared library, and it must stay thread-local (see InBarrierWait's note diff --git a/MobileGL/MG_Remote/Client/ClientSession.h b/MobileGL/MG_Remote/Client/ClientSession.h index 204d38ce..a8747100 100644 --- a/MobileGL/MG_Remote/Client/ClientSession.h +++ b/MobileGL/MG_Remote/Client/ClientSession.h @@ -193,7 +193,7 @@ namespace MobileGL::MG_Remote::Client { Wire::PipeWireEncoder& Encoder(); CapsMirror& Caps(); - // Emit one record and, if the barrier is armed, wait for it. `replyOut`/`replyBytes` + // Emit one record and wait for it unless the wait rule lets it go. `replyOut`/`replyBytes` // name where a kReplySlot answer lands; pass {nullptr, 0} for a call that has none. // Returns the record's seq, which is also its reply-slot id. // @@ -280,18 +280,13 @@ namespace MobileGL::MG_Remote::Client { // !willReadReply, and !willReadReply on a row with no reply slot, are Fatal by name: the // first would wait for an answer never sent, the second discards one never posted. - // MOBILEGL_IPC_VERB_BARRIER. False is the R-1 negative control and is EXPECTED to be - // red; it must be run once and the way it goes red recorded. - Bool BarrierArmed() const; - // ---- P5e (ra): the wait rule (CONTRACT-P5E §1, §2.3, §2.4, §2.5) ------------------- - // A CONJUNCTION OF THREE, LATCHED ONCE: `m_barrierArmed && Ipc.RunAhead && - // Caps().HasCap(kCapRunAheadApply)`. The third conjunct is the server's own statement - // that it applies an unbarriered record without reading client memory, so run-ahead is - // never something the client can turn on by itself - on Magma, and on Espryt until the - // integration commit publishes bit 10, this answers false and EmitAndWaitTails runs - // today's lockstep path byte for byte. + // A CONJUNCTION OF TWO, LATCHED ONCE: `Ipc.RunAhead && Caps().HasCap(kCapRunAheadApply)`. + // The second conjunct is the server's own statement that it applies an unbarriered record + // without reading client memory, so run-ahead is never something the client can turn on + // by itself - on Magma, and on Espryt until the integration commit publishes bit 10, + // this answers false and EmitAndWaitTails runs today's lockstep path byte for byte. // // LATCHED AT THE FIRST CAPS ADOPTION AFTER Start, AND A LATER SNAPSHOT MAY ONLY TURN IT // OFF. A caps re-run cannot promote a lockstep server to a run-ahead one mid-frame: @@ -540,7 +535,6 @@ namespace MobileGL::MG_Remote::Client { Wire::PipeWireEncoder m_encoder; Wire::SegmentTable m_segments; - Bool m_barrierArmed = true; // P5e (ra): the latch of RunAheadArmed() and the fact that it has been taken once. Bool m_runAheadArmed = false; Bool m_runAheadLatched = false; diff --git a/MobileGL/MG_Remote/Transport/SessionRings.h b/MobileGL/MG_Remote/Transport/SessionRings.h index 0e0ebbe2..01e77160 100644 --- a/MobileGL/MG_Remote/Transport/SessionRings.h +++ b/MobileGL/MG_Remote/Transport/SessionRings.h @@ -267,9 +267,8 @@ namespace MobileGL::MG_Remote::Transport { // encourages batching the publish, so the shared watermark may lag the // emitter - and a drain that waits for `appliedSeq >= submittedSeq` would // then under-wait and free an emitter's var-tail while a record still - // names it. With the verb barrier armed the two are equal; with - // MOBILEGL_IPC_VERB_BARRIER=0, R-1's negative control which the phase has - // to run once, they are not. + // names it. Run-ahead and the batched waits publish without waiting, so + // at teardown the two may differ. std::uint64_t LastPublishedSeq() const { return m_lastPublishedSeq; } // The verb barrier's wait, AND the reply's wait: they are the same wait diff --git a/MobileGL/MG_Test/Wire/InitialCapsStartupTest.cpp b/MobileGL/MG_Test/Wire/InitialCapsStartupTest.cpp index 9743c64e..e394b99e 100644 --- a/MobileGL/MG_Test/Wire/InitialCapsStartupTest.cpp +++ b/MobileGL/MG_Test/Wire/InitialCapsStartupTest.cpp @@ -54,7 +54,6 @@ namespace { ::alarm(10); MG_Config::Transport = MG_Config::TransportMode::Spawn; MG_Config::Ipc.RunAhead = 1; - MG_Config::Ipc.VerbBarrier = 1; int reserve = ::socket(AF_INET, SOCK_STREAM, 0); ASSERT_GE(reserve, 0); sockaddr_in address{}; diff --git a/MobileGL/MG_Test/Wire/RemoteClientE1Controls.inc b/MobileGL/MG_Test/Wire/RemoteClientE1Controls.inc index 607eace1..0434e358 100644 --- a/MobileGL/MG_Test/Wire/RemoteClientE1Controls.inc +++ b/MobileGL/MG_Test/Wire/RemoteClientE1Controls.inc @@ -44,9 +44,6 @@ void CheckE1Boundary(Bool serverCap, MGPWireOp op, Bool expectWait, const char* E1Emit emit = E1Emit::Rule) { const auto child = RunInChild([=] { ::alarm(15); - const char* barrier = std::getenv("MOBILEGL_IPC_VERB_BARRIER"); - if (barrier && std::strcmp(barrier, "0") && std::strcmp(barrier, "1")) ::_exit(80); - MG_Config::Ipc.VerbBarrier = barrier ? static_cast(barrier[0] - '0') : 1; MG_Config::Ipc.BatchWaits = 1; MG_Config::Ipc.RunAhead = 1; MG_Config::Ipc.SpinUs = 0; @@ -84,9 +81,9 @@ void CheckE1Boundary(Bool serverCap, MGPWireOp op, Bool expectWait, const char* if (session.WaitForApplied(seq, 2000) != Transport::SessionWait::Reached) ::_exit(85); if (seq <= before || peer.seen.load() != 1 || session.Control()->Progress.appliedSeq.load() < seq) ::_exit(86); const Bool correct = expectWait ? parked && appliedBeforeReturn : !parked && !appliedBeforeReturn; - std::printf("E1 observation: op=%s cap=%u barrier=%u parked=%u applied_before_return=%u emitted=1 peer_seen=1\n", + std::printf("E1 observation: op=%s cap=%u emit=%s parked=%u applied_before_return=%u emitted=1 peer_seen=1\n", op == MGPWireOp::ApplierReset ? "ApplierReset" : "Clear", - static_cast(serverCap), MG_Config::Ipc.VerbBarrier, + static_cast(serverCap), emit == E1Emit::PublishOnly ? "publish-only" : "rule", static_cast(parked), static_cast(appliedBeforeReturn)); std::fflush(stdout); session.Stop(); diff --git a/MobileGL/MG_Test/Wire/RemoteClientTest.cpp b/MobileGL/MG_Test/Wire/RemoteClientTest.cpp index bf08e273..1361f21a 100644 --- a/MobileGL/MG_Test/Wire/RemoteClientTest.cpp +++ b/MobileGL/MG_Test/Wire/RemoteClientTest.cpp @@ -2730,29 +2730,6 @@ TEST(RemoteRunAhead, TheKnobAloneDoesNotArmRunAheadWithoutTheServersCapBit) { ExpectChildSuccess(child); } -// §1 again, from the other side: MOBILEGL_IPC_VERB_BARRIER=0 is the LOCKSTEP arm's negative -// control and it disarms run-ahead outright, because the barrier is the first term of the -// conjunction. Under run-ahead its documented red is the first barriered row's stale pull - -// that one is a scenario, not a unit case; what is pinned here is that the two controls do not -// silently compose into a third mode nobody designed. -TEST(RemoteRunAhead, ClearingTheVerbBarrierDisarmsRunAheadEvenWithTheCapBit) { - const auto child = RunInChild([] { - MG_Config::Ipc.RunAhead = 1; - MG_Config::Ipc.VerbBarrier = 0; - ::alarm(15); - MG_Config::Transport = MG_Config::TransportMode::InProcess; - Srv::ServerSessionInstance().SetCapabilityBits(static_cast(MG_Pipe::kCapRunAheadApply)); - Srv::ServerSessionInstance().SetConsumedSubsystems(kMGPipeSubsystemsMigratedAtP4a); - Srv::ServerSessionInstance().SetBackend(ControlCapsPeer()); - if (ClientSessionInstance().Start(MG_Config::TransportMode::InProcess, {}) != MOBILEGL_OK) { - ::_exit(81); - } - if (ClientSessionInstance().RunAheadArmed()) ::_exit(101); - ClientSessionInstance().Stop(); - }); - ExpectChildSuccess(child); -} - // §2.4's RED-ONCE, BY COUNT. With a credit of 1 the client may have one present in flight, so // the second and third presents each pay the credit before they encode - `credit-waits` is 2 // after three presents and the present-ack watermark has reached 2. Delete the diff --git a/MobileGL/MG_Test/Wire/SessionTest.cpp b/MobileGL/MG_Test/Wire/SessionTest.cpp index 38b66219..c8bfe40a 100644 --- a/MobileGL/MG_Test/Wire/SessionTest.cpp +++ b/MobileGL/MG_Test/Wire/SessionTest.cpp @@ -1244,9 +1244,8 @@ TEST(SessionTest, ABorrowedSlotIsNotHandedBackUntilItIsReleased) { // q-1. Teardown's drain keys on the PRODUCER's own last-published seq, not on // RingControl::submittedSeq: Ring.h's header comment permits that watermark to be published lazily, so a // drain that trusted it would under-wait and free an emitter-owned var-tail while a record -// still names it. With the verb barrier armed the two are equal; under -// MOBILEGL_IPC_VERB_BARRIER=0 - R-1's negative control, which the phase must run once - they -// are not. +// still names it. Run-ahead and the batched waits publish without waiting, so at teardown the +// two may differ. TEST(SessionTest, TheProducerRemembersWhatItPublishedEvenIfTheWatermarkLags) { SessionFixture session; ASSERT_TRUE(session.Build(TestSizes())); diff --git a/MobileGL/MG_Test/Wire/StreamClientPublicationTest.cpp b/MobileGL/MG_Test/Wire/StreamClientPublicationTest.cpp index f63329a5..92c958d3 100644 --- a/MobileGL/MG_Test/Wire/StreamClientPublicationTest.cpp +++ b/MobileGL/MG_Test/Wire/StreamClientPublicationTest.cpp @@ -57,7 +57,6 @@ namespace { ::alarm(5); MG_Config::Transport = MG_Config::TransportMode::Spawn; MG_Config::Ipc.RunAhead = 1; - MG_Config::Ipc.VerbBarrier = 1; MG_Config::Ipc.BatchWaits = 1; MG_Config::Ipc.PresentCredit = 3; Transport::SessionSegmentSizes sizes; diff --git a/docs/Disaggregated/design/09-build-switches-counters.md b/docs/Disaggregated/design/09-build-switches-counters.md index 3e447feb..336a30f9 100644 --- a/docs/Disaggregated/design/09-build-switches-counters.md +++ b/docs/Disaggregated/design/09-build-switches-counters.md @@ -64,7 +64,6 @@ CMake:`MOBILEGL_BUILD_DISAGGREGATED`(OFF)、`MOBILEGL_BUILD_DISAGGREGATED_ | `MOBILEGL_IPC_SURFACE` | `offscreen` | `server` = 使用 server 自有窗口,client 无头(P12) | | `MOBILEGL_IPC_RING_MB` / `MOBILEGL_IPC_STAGE_MB` | 8 / 32 | `SEG_CMD` / `SEG_STAGE`;stage 的 1/4 是内容分块预算 | | `MOBILEGL_IPC_RUN_AHEAD` | 1 | P5e run-ahead;只是合取式的一半(server 须发布 `kCapRunAheadApply`);`0` 是 A/B 对照 | -| `MOBILEGL_IPC_VERB_BARRIER` | 1 | `0` 只作阴性对照,且同时关掉 run-ahead | | `MOBILEGL_FRAMES_IN_FLIGHT` | 3 | 1..64,两个后端共用(旧名 `MOBILEGL_MAGMA_FRAMESINFLIGHT` 为弃用别名):Magma 的帧上下文数;Espryt 在 present S 后等待帧 S+1-N 完成;split 的 present credit 由它导出为 max(1, N-2)(P15) | | `MOBILEGL_IPC_PRESENT_CREDIT` | 由 `MOBILEGL_FRAMES_IN_FLIGHT` 导出(默认 1) | 1..8,§14;显式设置覆盖导出值,仅供实验 | | `MOBILEGL_IPC_POLL_ESCALATE` | 64 | 未报告 fence 的零超时轮询本地答"未完成",同一 fence 连续第 N 次才往返(P10,`CONTRACT-P10.md` §1);`0` = 每次轮询都往返,是 A/B 对照 | diff --git a/docs/Disaggregated/design/10-phase-shapes.md b/docs/Disaggregated/design/10-phase-shapes.md index 31a4206c..ff621645 100644 --- a/docs/Disaggregated/design/10-phase-shapes.md +++ b/docs/Disaggregated/design/10-phase-shapes.md @@ -14,4 +14,4 @@ | 17.4 | lane 隔离(P5) | 每条 split 条目私有日志;E1 与 E3(a) 的对照是常驻用例(`RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait`、`PersistentCoherentMapScenario.ThePushIsTheOnlyRouteAWriteTakesToTheServer`),不重跑 lane | 同上 | | 17.5 | class-C verb 迁移(P5b) | 迁移顺序由动态普查决定;一次迁移 = 一个发射器 + 一个 sink 体;记录逐字带 GL 调用参数,未测量的形式按名拒绝(规则 D) | [`docs/archive/notes/p5b/README.md`](../../archive/notes/p5b/README.md) | | 17.6 | 共享地址空间访问归零(P5c) | server 端纹理 staged shadow;`SEG_EVENT` 是唯一反向通道;sink / twin 按记录句柄解析;`applier_reset` / `object_death` 控制记录;角色守卫 `Fatal{RoleViolation}` | [`docs/archive/notes/p5c/README.md`](../../archive/notes/p5c/README.md) | -| 17.7 | run-ahead(P5e) | 规则 F:unbarriered 记录的 apply 不读任何 client 内存(违反即具名 Fatal,与 strict 开关无关);`gPipeInputs` 是 server 角色内存;`RunAheadArmed()` 在首次 caps 采纳时锁存,只能关不能开;`RUN_AHEAD=0` 是 A/B 对照,`VERB_BARRIER=0` 会连带关掉 run-ahead | [`docs/archive/notes/p5e/README.md`](../../archive/notes/p5e/README.md) | +| 17.7 | run-ahead(P5e) | 规则 F:unbarriered 记录的 apply 不读任何 client 内存(违反即具名 Fatal,与 strict 开关无关);`gPipeInputs` 是 server 角色内存;`RunAheadArmed()` 在首次 caps 采纳时锁存,只能关不能开;`RUN_AHEAD=0` 是 A/B 对照 | [`docs/archive/notes/p5e/README.md`](../../archive/notes/p5e/README.md) | diff --git a/docs/ci/ci-cleanup-log.md b/docs/ci/ci-cleanup-log.md index cfbd2140..cae0f090 100644 --- a/docs/ci/ci-cleanup-log.md +++ b/docs/ci/ci-cleanup-log.md @@ -57,6 +57,7 @@ them wrong. | 2026-10-18 | `Negative controls (barrier, map push)` (`scripts/ci/split_negative_controls.sh`; skip-census lane `junit-integration-split/control`) | Test / `integration-split` | it reran the split entries with `MOBILEGL_IPC_VERB_BARRIER=0` and `MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0`, two product knobs that exist only for it; what was left without them (the ownership check and the baseline tally) repeats `SplitLogPaths.PrivateAndDistinct` and the lane step's own `junit_tally.py --require-split-ran` | E1: `RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait` (unit, always on); E3(a): `PersistentCoherentMapScenario.ThePushIsTheOnlyRouteAWriteTakesToTheServer` on the inproc, spawn, tcp and small-ring split entries (always on) | | 2026-10-18 | `scripts/ci/wait_boundary_negative_control.py` | Test / `integration-split` | E1's body inside the step above: the three boundary cases rerun with the barrier off | `RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait`: the same ApplierReset published with no wait must read parked=0, the observation the owed waits read as parked=1 | | 2026-10-18 | `scripts/ci/control_smoke_test.sh`, `scripts/ci/testdata/stub_ctest.sh`, `scripts/ci/testdata/split_private_log_smoke.sh`, and the `reset` / `results` / `assertion` / `evidence` modes of `split_log_paths.py` | Test / pipe-gates (R-16) | smoke cases and helpers of the step above only | none needed | +| 2026-10-18 | unit `RemoteRunAhead.ClearingTheVerbBarrierDisarmsRunAheadEvenWithTheCapBit`, and the `MOBILEGL_IPC_VERB_BARRIER` knob with its arm in the shipped client (`ClientSession`: the free-running `EmitAndWaitTails` return, the run-ahead latch term, the `gPipeInputs` guard's early return, the `verb-barrier=` field of the `Config: IPC` line) | Test / unit (split); product code | `0` was never a product mode, only E1's negative control, retired above; the unit case pinned that the control also disarmed run-ahead | `RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait`; `MOBILEGL_IPC_RUN_AHEAD=0` stays the lockstep A/B arm | ## Kept after investigation diff --git a/scripts/data/skip_census_baseline.json b/scripts/data/skip_census_baseline.json index 56976b09..30305f2c 100644 --- a/scripts/data/skip_census_baseline.json +++ b/scripts/data/skip_census_baseline.json @@ -11207,7 +11207,6 @@ "RemoteRunAhead.AnEventBurstBehindAnUnwaitedSequenceFlowControlsInsteadOfAborting", "RemoteRunAhead.AnIndexedDrawVerbIsUnbarrieredAndTouchesPipeInputsNotAtAll", "RemoteRunAhead.AnUnbarrieredVerbDoesNotFillPipeInputsAndIsAllowed", - "RemoteRunAhead.ClearingTheVerbBarrierDisarmsRunAheadEvenWithTheCapBit", "RemoteRunAhead.OnlyTheTextureHalfOfResourceSubDataWantsItsReply", "RemoteRunAhead.TheKnobAloneDoesNotArmRunAheadWithoutTheServersCapBit", "RemoteWaitBoundaryControl.AnUnwaitedPublishIsSeenAsNoWait", diff --git a/tools/trace_replay/README.md b/tools/trace_replay/README.md index a466391d..17b28241 100644 --- a/tools/trace_replay/README.md +++ b/tools/trace_replay/README.md @@ -460,11 +460,11 @@ stacks before treating a local result as a statement about CI. `run_tcp_matrix.py` uses a CTest JSON catalog plus the **current** `trace_cases.json`. It does not build, install an APK, or launch the remote server. For the formal -P6.5 run-ahead matrix, use `--require-run-ahead`. It forces `MOBILEGL_IPC_RUN_AHEAD=1` -and `MOBILEGL_IPC_VERB_BARRIER=1`, then requires `run-ahead ARMED` in each private -client log and rejects any `running lockstep` / `DISARMED` marker. The checkpoint -records `requested_arm` and `actual_arm`; strict resume cannot reuse an earlier -lockstep image pass. Start the intended server first, then run serially: +P6.5 run-ahead matrix, use `--require-run-ahead`. It forces `MOBILEGL_IPC_RUN_AHEAD=1`, +then requires `run-ahead ARMED` in each private client log and rejects any +`running lockstep` / `DISARMED` marker. The checkpoint records `requested_arm` and +`actual_arm`; strict resume cannot reuse an earlier lockstep image pass. Start the intended +server first, then run serially: ```bash ctest --test-dir /path/to/retrace-build --show-only=json-v1 > /tmp/trace-catalog.json diff --git a/tools/trace_replay/benchmark_tcp_credits.py b/tools/trace_replay/benchmark_tcp_credits.py index 0a3e7aab..967afae5 100644 --- a/tools/trace_replay/benchmark_tcp_credits.py +++ b/tools/trace_replay/benchmark_tcp_credits.py @@ -59,7 +59,7 @@ def measure(args, case, credit, work): env = dict(os.environ, MOBILEGL_TRANSPORT='spawn', MOBILEGL_IPC_CONTROL=args.endpoint, MOBILEGL_IPC_DATA='stream', MOBILEGL_IPC_TOKEN=args.token, MOBILEGL_IPC_REQUIRE_SAME_BUILD='1', MOBILEGL_IPC_LOG_FORWARD='1', MOBILEGL_PIPE_STATS='1', MOBILEGL_PIPE_STATS_PERIOD='1', - MOBILEGL_IPC_PRESENT_CREDIT=str(credit), MOBILEGL_IPC_RUN_AHEAD='1', MOBILEGL_IPC_VERB_BARRIER='1', + MOBILEGL_IPC_PRESENT_CREDIT=str(credit), MOBILEGL_IPC_RUN_AHEAD='1', MOBILEGL_IPC_BATCH_WAITS='1', MOBILEGL_BACKEND_TYPE='DirectGLES', MOBILEGL_IPC_STRICT_ERRORS='0', MOBILEGL_IPC_ROLE_SPLIT_STATE='0', MOBILEGL_IPC_AUDIT='0') for name in ('MOBILEGL_IPC_DIAL', 'MOBILEGL_IPC_SERVER_PATH'): diff --git a/tools/trace_replay/measure_loopback_cpu.py b/tools/trace_replay/measure_loopback_cpu.py index 30c26676..18470916 100644 --- a/tools/trace_replay/measure_loopback_cpu.py +++ b/tools/trace_replay/measure_loopback_cpu.py @@ -58,7 +58,7 @@ def run(args, case, transport, repeat): out.mkdir(parents=True) env = dict(os.environ, MOBILEGL_TRANSPORT='spawn', MOBILEGL_BACKEND_TYPE='DirectGLES', MOBILEGL_IPC_SERVER_PATH=str(args.server), MOBILEGL_PIPE_STATS='1', MOBILEGL_PIPE_STATS_PERIOD='1', - MOBILEGL_IPC_PRESENT_CREDIT='1', MOBILEGL_IPC_RUN_AHEAD='1', MOBILEGL_IPC_VERB_BARRIER='1', + MOBILEGL_IPC_PRESENT_CREDIT='1', MOBILEGL_IPC_RUN_AHEAD='1', MOBILEGL_IPC_BATCH_WAITS='1', MOBILEGL_IPC_SPIN_US='50', MOBILEGL_IPC_STRICT_ERRORS='0', MOBILEGL_IPC_ROLE_SPLIT_STATE='0', MOBILEGL_IPC_AUDIT='0', LIBGL_ALWAYS_SOFTWARE='1', EGL_PLATFORM='surfaceless', diff --git a/tools/trace_replay/measure_tcp_stage_burst.py b/tools/trace_replay/measure_tcp_stage_burst.py index 71c87c36..714a3371 100644 --- a/tools/trace_replay/measure_tcp_stage_burst.py +++ b/tools/trace_replay/measure_tcp_stage_burst.py @@ -36,7 +36,7 @@ def run(args): MOBILEGL_IPC_REQUIRE_SAME_BUILD='1', MOBILEGL_IPC_LOG_FORWARD='1', MOBILEGL_BACKEND_TYPE='DirectGLES', MOBILEGL_PIPE_STATS='1', MOBILEGL_PIPE_STATS_PERIOD='1', MOBILEGL_IPC_RUN_AHEAD='1', - MOBILEGL_IPC_VERB_BARRIER='1', MOBILEGL_IPC_PRESENT_CREDIT='1', + MOBILEGL_IPC_PRESENT_CREDIT='1', MOBILEGL_LOG_FILE_PATH=str(args.out / 'mobilegl.log'), EGL_PLATFORM='surfaceless') for name in ('MOBILEGL_IPC_DIAL', 'MOBILEGL_IPC_SERVER_PATH'): os.environ.pop(name, None) diff --git a/tools/trace_replay/measure_transport_cpu.py b/tools/trace_replay/measure_transport_cpu.py index 880a041f..a782394e 100644 --- a/tools/trace_replay/measure_transport_cpu.py +++ b/tools/trace_replay/measure_transport_cpu.py @@ -118,7 +118,7 @@ def run(args, transport, case, repeat): env = dict(os.environ, MOBILEGL_TRANSPORT=transport, MOBILEGL_IPC_SERVER_PATH=str(args.server), MOBILEGL_PIPE_STATS='0', MOBILEGL_IPC_PRESENT_CREDIT='1', MOBILEGL_IPC_RUN_AHEAD='1', MOBILEGL_IPC_STRICT_ERRORS='0', MOBILEGL_IPC_ROLE_SPLIT_STATE='0', MOBILEGL_IPC_AUDIT='0', - MOBILEGL_IPC_VERB_BARRIER='1', MOBILEGL_IPC_BATCH_WAITS='1', MOBILEGL_IPC_SPIN_US='50', + MOBILEGL_IPC_BATCH_WAITS='1', MOBILEGL_IPC_SPIN_US='50', LIBGL_ALWAYS_SOFTWARE='1', EGL_PLATFORM='surfaceless', MESA_GL_VERSION_OVERRIDE='3.3', MESA_GLSL_VERSION_OVERRIDE='330') for key in ('MOBILEGL_IPC_CONTROL', 'MOBILEGL_IPC_DATA', 'MOBILEGL_IPC_TOKEN', 'MOBILEGL_IPC_DIAL', diff --git a/tools/trace_replay/run_tcp_matrix.py b/tools/trace_replay/run_tcp_matrix.py index 7578f856..e183c351 100644 --- a/tools/trace_replay/run_tcp_matrix.py +++ b/tools/trace_replay/run_tcp_matrix.py @@ -140,7 +140,6 @@ def case_environment(test, base, args, output=None): MOBILEGL_IPC_PRESENT_CREDIT=str(args.credit)) if getattr(args, "require_run_ahead", False): env["MOBILEGL_IPC_RUN_AHEAD"] = "1" - env["MOBILEGL_IPC_VERB_BARRIER"] = "1" if output is not None: env["MOBILEGL_LOG_FILE_PATH"] = str(output / "output/mobilegl.log") return env @@ -406,7 +405,7 @@ def run_case(plan, args, row): work = Path(row["work"]) console = work.parent / "runner.log" env = case_environment(plan["test"], args.base_env, args, work) - row["requested_arm"] = {key: env.get(key) for key in ("MOBILEGL_IPC_RUN_AHEAD", "MOBILEGL_IPC_VERB_BARRIER")} + row["requested_arm"] = {key: env.get(key) for key in ("MOBILEGL_IPC_RUN_AHEAD",)} props = properties(plan["test"]) cwd = props.get("WORKING_DIRECTORY", str(args.source)) def wake(): @@ -456,7 +455,7 @@ def main(argv=None): parser.add_argument("--credit", type=int, choices=(1, 2, 3), default=2) parser.add_argument("--resume", action="store_true") parser.add_argument("--require-run-ahead", action="store_true", - help="require private-client ARMED proof, no lockstep fallback/DISARMED; force RUN_AHEAD=1 and VERB_BARRIER=1") + help="require private-client ARMED proof, no lockstep fallback/DISARMED; force RUN_AHEAD=1") parser.add_argument("--idle-seconds", type=float, default=300) parser.add_argument("--max-seconds", type=float, default=7200) parser.add_argument("--wake-adb-serial", help="explicit opt-in: KEYCODE_WAKEUP every 15 seconds while a case runs") diff --git a/tools/trace_replay/test_run_tcp_matrix.py b/tools/trace_replay/test_run_tcp_matrix.py index 68c670b9..36d18828 100644 --- a/tools/trace_replay/test_run_tcp_matrix.py +++ b/tools/trace_replay/test_run_tcp_matrix.py @@ -37,7 +37,7 @@ if behavior!='no-result': actual=work/'output/actual.png';actual.write_bytes(b'fixture-image') endpoint=os.environ['MOBILEGL_IPC_CONTROL'].removeprefix('tcp://') arm=os.environ.get('CASE_ARM','armed') - if arm=='respect-env':arm='armed' if os.environ.get('MOBILEGL_IPC_RUN_AHEAD')=='1' and os.environ.get('MOBILEGL_IPC_VERB_BARRIER')=='1' else 'lockstep' + if arm=='respect-env':arm='armed' if os.environ.get('MOBILEGL_IPC_RUN_AHEAD')=='1' else 'lockstep' line={'armed':'run-ahead ARMED\n','lockstep':'running lockstep\n','disarmed':'run-ahead ARMED\nrun-ahead DISARMED\n','server-only':''}[arm] (work/'output/mobilegl.client.log').write_text('control=tcp data=stream server='+endpoint+' pid=123 dial=connect\n'+line) if arm=='server-only':(work/'output/mobilegl.server.log').write_text('run-ahead ARMED\n') @@ -116,11 +116,11 @@ class MatrixTests(unittest.TestCase): test['properties'][0]['value'] += list(entries) self.catalog.write_text(json.dumps(catalog)) - def test_required_arm_forces_both_environment_knobs_and_records_actual_arm(self): - self.set_arm('respect-env',['MOBILEGL_IPC_RUN_AHEAD=0','MOBILEGL_IPC_VERB_BARRIER=0']) + def test_required_arm_forces_the_run_ahead_knob_and_records_actual_arm(self): + self.set_arm('respect-env',['MOBILEGL_IPC_RUN_AHEAD=0']) self.assertEqual(self.run_main('--require-run-ahead'),0) row=self.checkpoint()[0] - self.assertEqual(row['requested_arm'],{'MOBILEGL_IPC_RUN_AHEAD':'1','MOBILEGL_IPC_VERB_BARRIER':'1'}) + self.assertEqual(row['requested_arm'],{'MOBILEGL_IPC_RUN_AHEAD':'1'}) self.assertEqual(row['actual_arm'],{'armed':True,'lockstep':False,'disarmed':False}) self.assertEqual(self.run_main('--require-run-ahead','--resume'),0) self.assertEqual(len(self.checkpoint()),1) @@ -337,7 +337,7 @@ class MatrixTests(unittest.TestCase): def test_directvulkan_run_ahead_proof_and_checkpoint_keys_are_per_backend(self): self.write_inputs(backends=('DirectGLES','DirectVulkan')) - self.set_arm('respect-env',['MOBILEGL_IPC_RUN_AHEAD=0','MOBILEGL_IPC_VERB_BARRIER=0']) + self.set_arm('respect-env',['MOBILEGL_IPC_RUN_AHEAD=0']) self.assertEqual(self.run_main('--backend','DirectGLES','--backend','DirectVulkan', '--require-run-ahead'),0) rows=self.checkpoint() diff --git a/tools/trace_replay/test_run_trace_case.py b/tools/trace_replay/test_run_trace_case.py index c94bd72f..cec648c3 100644 --- a/tools/trace_replay/test_run_trace_case.py +++ b/tools/trace_replay/test_run_trace_case.py @@ -259,7 +259,7 @@ class RunTraceCaseTests(unittest.TestCase): 'a leg whose transport block was skipped must fail the checker') # MGTRACE_EXPECT_IPC: the client's IPC line must carry every token, whole. - IPC = 'Config: IPC ring=8MiB verb-barrier=1 run-ahead={ra} present-credit=1 strict={st} audit=0 role-split-state={rs} x' + IPC = 'Config: IPC ring=8MiB run-ahead={ra} present-credit=1 strict={st} audit=0 role-split-state={rs} x' def ipc_logs(self, ra='1', st='0', rs='1', line=True): logs = good_logs('spawn')