mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Refactor, Test] (docs/ci, docs/Disaggregated, MG_IntegrationTest/Scenarios, MG_State/GLState, MG_Test, MG_Test/Buffer, MG_Util/Metrics, MobileGL, scripts/data): fix the persistent-map push block at 64 KiB
- retires SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited
This commit is contained in:
@@ -550,10 +550,6 @@ namespace MobileGL::MG_Config {
|
||||
// by design": no forced sync, so a one-frame respecify-and-draw loop grows without bound
|
||||
// and MagmaWireReclaimScenario's watermark cases must go red.
|
||||
Uint32 WireDeferredMb = 64;
|
||||
// MOBILEGL_IPC_PERSISTENT_BLOCK_KB: block granularity of the persistent-map push.
|
||||
// 0 IS A NEGATIVE CONTROL, NOT "unlimited": it disables the push, and
|
||||
// PersistentCoherentMapScenario must go RED under it (exit gate E3(a)).
|
||||
Uint32 PersistentBlockKb = 64;
|
||||
// MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS: 1 = the persistent-map push ships only
|
||||
// blocks whose xxHash64 changed since the last push, instead of the whole mapped
|
||||
// range every verb. 0 restores the whole-range push (A/B control).
|
||||
|
||||
@@ -714,11 +714,11 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
// changes the wall clock by seconds (the P12 sweep: 28.3 s at 1 down to 10.8 s at 6) a
|
||||
// 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 "
|
||||
"create-window=%u pbo-readback-sync=%u poll-escalate=%u "
|
||||
"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,
|
||||
ipc.CreateWindow, ipc.PboReadbackSync, ipc.PollEscalate,
|
||||
ipc.AdoptTier == 0 ? "0"
|
||||
: ipc.AdoptTier == 1 ? "1"
|
||||
: ipc.AdoptTier == 2 ? "2"
|
||||
@@ -735,9 +735,6 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
// P7 wave 4 M2 (Config.h has the semantics). 0 is admitted ON PURPOSE as the negative
|
||||
// control: no forced sync, and MagmaWireReclaimScenario's watermark case must go red.
|
||||
ipc.WireDeferredMb = QueryEnvUint32("MOBILEGL_IPC_WIRE_DEFERRED_MB", 64, 0, 65536);
|
||||
// 0 is admitted ON PURPOSE and is the negative control of exit gate E3(a): it turns
|
||||
// the persistent-map push OFF, and PersistentCoherentMapScenario must go red.
|
||||
ipc.PersistentBlockKb = QueryEnvUint32("MOBILEGL_IPC_PERSISTENT_BLOCK_KB", 64, 0, 65536);
|
||||
// Whole-range push is the 0 arm; with it on (default) only blocks whose
|
||||
// xxHash64 changed since the last push are shipped.
|
||||
ipc.PersistentHashSuppress = QueryEnvUint32("MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS", 1, 0, 1);
|
||||
@@ -751,10 +748,6 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
"server never forces a sync for orphaned wire buffer stores, so a long frame "
|
||||
"that respecifies and draws holds every one of them until the frame ends");
|
||||
}
|
||||
if (ipc.PersistentBlockKb == 0) {
|
||||
MGLOG_W("Config: MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0 is the E3(a) NEGATIVE CONTROL: "
|
||||
"the persistent-map push is OFF and a coherent-map scenario must go red");
|
||||
}
|
||||
}
|
||||
|
||||
void Init() {
|
||||
|
||||
@@ -593,11 +593,9 @@ void main() { oColor = vec4(vColor, 1.0); }
|
||||
"a window with "
|
||||
<< kDrawsInTheWindow
|
||||
<< " writes and as many draws through a live coherent mapping cannot have pushed "
|
||||
"zero bytes. Zero here with MOBILEGL_IPC_PERSISTENT_BLOCK_KB at its default "
|
||||
"means the push is not reaching this buffer - which is a DIFFERENT defect from "
|
||||
"the store having been adopted, and the arm assertion above has already ruled "
|
||||
"that one out. Zero with the knob set to 0 is exit gate E3(a)'s negative control "
|
||||
"working as intended. Line: "
|
||||
"zero bytes. Zero here means the push is not reaching this buffer - which is a "
|
||||
"DIFFERENT defect from the store having been adopted, and the arm assertion "
|
||||
"above has already ruled that one out. Line: "
|
||||
<< window.line;
|
||||
} else {
|
||||
// Recorded, not asserted: on this arm the number is whatever the driver's adoption
|
||||
|
||||
@@ -501,14 +501,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
// carries are real, current and the cheapest honest ones there are. A zero-length
|
||||
// record would have been the alternative and it is illegal by contract rule A.
|
||||
if (m_size == 0) return;
|
||||
const Uint64 blockBytes = MG_Record::PersistentMapTracker::BlockBytes();
|
||||
// MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0 TURNS THE WHOLE MECHANISM OFF, STATE RECORD
|
||||
// INCLUDED (E3(a)). An earlier cut skipped the blocks and still shipped a whole buffer
|
||||
// here, which meant an unmap delivered the bytes the control exists to withhold - and
|
||||
// a negative control that still delivers them is not a control. With the knob at 0
|
||||
// nothing is published and nothing is pushed, so the probe answers clean, the frame
|
||||
// draws the last uploaded bytes, and PersistentCoherentMapScenario goes red.
|
||||
if (blockBytes == 0) return;
|
||||
constexpr Uint64 blockBytes = MG_Record::PersistentMapTracker::BlockBytes();
|
||||
const SizeT length = blockBytes >= static_cast<Uint64>(m_size) ? m_size : static_cast<SizeT>(blockBytes);
|
||||
NotifySubData(0, length);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace MobileGL {
|
||||
// behaviour and D-J forbids it. The pull build compiles none of it, which is also
|
||||
// how G1 holds over a file this central.
|
||||
|
||||
// ONE MOBILEGL_IPC_PERSISTENT_BLOCK_KB BLOCK of the mapped span, emitted through
|
||||
// ONE BLOCK of the mapped span (PersistentMapTracker::BlockBytes), emitted through
|
||||
// the private NotifySubData - the same serial, the same defined-content flag, the
|
||||
// same record - so the split arm and the monolith arm differ in HOW the span is
|
||||
// cut and in nothing else. Called only by
|
||||
|
||||
@@ -724,10 +724,6 @@ namespace MobileGL::MG_Record {
|
||||
return *instance;
|
||||
}
|
||||
|
||||
Uint64 PersistentMapTracker::BlockBytes() {
|
||||
return static_cast<Uint64>(MG_Config::RecordArm.PersistentBlockKb) * 1024ull;
|
||||
}
|
||||
|
||||
Bool PersistentMapTracker::PushIsArmed() {
|
||||
// P13 W4a: the record arm's buffer reads never ask the frontend object to sync a map, so
|
||||
// the client pushes the mapped span wherever that arm runs - monolith's included.
|
||||
@@ -908,33 +904,7 @@ namespace MobileGL::MG_Record {
|
||||
Forget(buffer);
|
||||
return;
|
||||
}
|
||||
const Uint64 blockBytes = BlockBytes();
|
||||
// 0 IS THE NEGATIVE CONTROL, NOT "unlimited" (E3(a)). Pushing one whole-span block
|
||||
// here would make the control green for the wrong reason - it has to disable the
|
||||
// push, so that PersistentCoherentMapScenario draws the last uploaded bytes and goes
|
||||
// red exactly the way an unpushed map does.
|
||||
//
|
||||
// AND IT SAYS SO, ONCE. Until now this was a silent `return`, so E3(a)'s red could
|
||||
// only ever be the scenario's pixel assertion and the control had no way to tell "the
|
||||
// push was disabled" apart from "the push was never armed, or never reached, or the
|
||||
// knob never got here" (joint-v1.md §3: "There is no Fatal for block size zero";
|
||||
// ID-65 assigns the line to x2). The control now requires BOTH: the pixel red AND
|
||||
// this line in the entry's own private log. It is MGLOG_W and not a Fatal because 0
|
||||
// is a legal configured value whose whole purpose is to keep running with the push
|
||||
// off; aborting here would turn every E3(a) entry into a subprocess abort and take
|
||||
// the pixel evidence with it.
|
||||
if (blockBytes == 0) {
|
||||
if (!m_blockZeroAnnounced) {
|
||||
m_blockZeroAnnounced = true;
|
||||
MGLOG_W("MGPipe: persistent-map push disabled - MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0 "
|
||||
"is exit gate E3(a)'s NEGATIVE CONTROL, not 'unlimited': a live "
|
||||
"persistent WRITE mapping's dirty blocks are NOT being pushed, so the "
|
||||
"server draws whatever bytes last crossed by some other route. A lane "
|
||||
"that stays green with this set is not getting its pixels from the push");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr Uint64 blockBytes = BlockBytes();
|
||||
const auto range = buffer.GetMappedRange();
|
||||
const Uint64 begin = static_cast<Uint64>(range.start);
|
||||
const Uint64 end = static_cast<Uint64>(range.end);
|
||||
@@ -1077,15 +1047,12 @@ namespace MobileGL::MG_Record {
|
||||
if (shadow != nullptr) {
|
||||
state = &m_blockHashes[buffer.GetLifetimeId()];
|
||||
const Uint64 blockCount = (end - begin + blockBytes - 1) / blockBytes;
|
||||
// A remap, a resize or a block-size change invalidates the layout the
|
||||
// hashes were taken against: reset, which forces one full push - the
|
||||
// conservative answer for a new layout.
|
||||
if (state->begin != begin || state->end != end || state->blockBytes != blockBytes ||
|
||||
state->hashes.size() != blockCount) {
|
||||
// A remap or a resize invalidates the layout the hashes were taken against:
|
||||
// reset, which forces one full push - the conservative answer for a new layout.
|
||||
if (state->begin != begin || state->end != end || state->hashes.size() != blockCount) {
|
||||
*state = {};
|
||||
state->begin = begin;
|
||||
state->end = end;
|
||||
state->blockBytes = blockBytes;
|
||||
state->hashes.assign(static_cast<SizeT>(blockCount), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,11 @@
|
||||
// pushing, and the two arms diverge with no test able to say so. IsLivePersistentMap() is the
|
||||
// single spelling; BufferObject::SyncPersistentMappedRange is held to it by a unit case.
|
||||
//
|
||||
// THE GRANULARITY. MOBILEGL_IPC_PERSISTENT_BLOCK_KB (default 64) blocks, keyed
|
||||
// {MGPipeHandle, blockIndex} - the key is implicit, because a block ships as an ORDINARY
|
||||
// resource_subdata record whose destination range is [blockIndex * blockBytes, + blockBytes).
|
||||
// NO NEW RECORD KIND: the existing record is already chunked by
|
||||
// MGPipeForEachSubDataRecordRange and already acceptance-gated, and a second way to say
|
||||
// "these bytes go there" is a second way to get it wrong. A block size of 0 is E3(a)'s
|
||||
// NEGATIVE CONTROL and means "push nothing" - not "one unlimited block" - so
|
||||
// PersistentCoherentMapScenario must go red under it.
|
||||
// THE GRANULARITY. 64 KiB blocks (BlockBytes()), keyed {MGPipeHandle, blockIndex} - the key
|
||||
// is implicit, because a block ships as an ORDINARY resource_subdata record whose destination
|
||||
// range is [blockIndex * blockBytes, + blockBytes). NO NEW RECORD KIND: the existing record is
|
||||
// already chunked by MGPipeForEachSubDataRecordRange and already acceptance-gated, and a second
|
||||
// way to say "these bytes go there" is a second way to get it wrong.
|
||||
//
|
||||
// Only changed blocks ship. At each validate point a member pushes just the blocks written
|
||||
// since its last push. A map the mprotect write-fault tracker holds (MOBILEGL_PIPE_PERSISTENT_MPROTECT;
|
||||
@@ -101,8 +98,8 @@ namespace MobileGL::MG_Record {
|
||||
// client-exclusive). Leaks at exit for ID-8's reason, once per role-local singleton.
|
||||
static PersistentMapTracker& Instance();
|
||||
|
||||
// MOBILEGL_IPC_PERSISTENT_BLOCK_KB * 1024. Zero means the push is OFF (E3(a)).
|
||||
static Uint64 BlockBytes();
|
||||
// The push's block size (THE GRANULARITY above).
|
||||
static constexpr Uint64 BlockBytes() { return 64ull * 1024ull; }
|
||||
// Transport != Monolith. The whole module is inert on the monolith path: an extra
|
||||
// resource_subdata record there would be new behaviour, which D-J forbids.
|
||||
static Bool PushIsArmed();
|
||||
@@ -154,7 +151,6 @@ namespace MobileGL::MG_Record {
|
||||
void ResetCountersForTest() {
|
||||
m_blocksPushed = 0;
|
||||
m_bytesPushed = 0;
|
||||
m_blockZeroAnnounced = false;
|
||||
}
|
||||
// Unit tests only: clears the membership, the hash cache and the mprotect tracked
|
||||
// slots (restoring every tracked page writable first), and resets the counters.
|
||||
@@ -225,7 +221,6 @@ namespace MobileGL::MG_Record {
|
||||
struct BlockHashState {
|
||||
Uint64 begin = 0;
|
||||
Uint64 end = 0;
|
||||
Uint64 blockBytes = 0;
|
||||
Vector<Uint64> hashes;
|
||||
};
|
||||
UnorderedMap<Uint64, BlockHashState> m_blockHashes;
|
||||
@@ -252,11 +247,6 @@ namespace MobileGL::MG_Record {
|
||||
// ran them once (the two Members hooks) - the guard's thread-local read was a
|
||||
// measurable per-buffer-per-draw cost on the emutls path.
|
||||
void PushBlocksForChecked(MG_State::GLState::BufferObject& buffer);
|
||||
// E3(a)'s diagnostic is emitted ONCE per process. PushBlocksFor runs at every validate
|
||||
// point of every member, so an unlatched MGLOG_W would be one line per draw per mapping
|
||||
// - and a control that has to grep a log cannot tell a message that fired from a
|
||||
// message that flooded.
|
||||
Bool m_blockZeroAnnounced = false;
|
||||
};
|
||||
|
||||
// What the client's emit table calls immediately BEFORE emitting any verb that can read a
|
||||
|
||||
@@ -86,13 +86,11 @@ namespace {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
m_transport = MG_Config::Transport;
|
||||
m_blockKb = MG_Config::RecordArm.PersistentBlockKb;
|
||||
m_adoptTier = MG_Config::Ipc.AdoptTier;
|
||||
m_pipeStats = MG_Config::Features.PipeStats;
|
||||
m_context = MG_State::pGLContext.Take();
|
||||
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
|
||||
MG_Config::Transport = MG_Config::TransportMode::InProcess;
|
||||
MG_Config::RecordArm.PersistentBlockKb = 64;
|
||||
MG_Config::Ipc.AdoptTier = 2;
|
||||
MG_Config::Features.PipeStats = true;
|
||||
MG_Util::PipeStats::Init();
|
||||
@@ -108,7 +106,6 @@ namespace {
|
||||
PersistentMapTracker::Instance().ClearForTest();
|
||||
MG_State::pGLContext = Move(m_context);
|
||||
MG_Config::Transport = m_transport;
|
||||
MG_Config::RecordArm.PersistentBlockKb = m_blockKb;
|
||||
MG_Config::Ipc.AdoptTier = m_adoptTier;
|
||||
MG_Config::Features.PipeStats = m_pipeStats;
|
||||
MG_Util::PipeStats::Init();
|
||||
@@ -121,7 +118,6 @@ namespace {
|
||||
}
|
||||
|
||||
MG_Config::TransportMode m_transport = MG_Config::TransportMode::Monolith;
|
||||
Uint32 m_blockKb = 64;
|
||||
Uint32 m_adoptTier = 2;
|
||||
Bool m_pipeStats = false;
|
||||
SharedPtr<MG_State::GLState::GLContext> m_context;
|
||||
@@ -463,35 +459,6 @@ TEST_F(SplitBufferSet, BothEdgesOfAWriteMapPublishOneStateRecord) {
|
||||
"the second the record stays dirty for the buffer's life";
|
||||
}
|
||||
|
||||
// E3(a)'s NEGATIVE CONTROL: 0 disables the push, it does not mean "one unlimited block" - and
|
||||
// it disables the STATE RECORDS with it. An earlier cut skipped the blocks and still shipped a
|
||||
// whole buffer at unmap, so a scenario that unmapped before reading back went green and the
|
||||
// control was dead.
|
||||
TEST_F(SplitBufferSet, AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited) {
|
||||
MG_Config::RecordArm.PersistentBlockKb = 0;
|
||||
constexpr SizeT kSize = 128u * 1024u;
|
||||
auto buffer = MakeBuffer(23u, kSize);
|
||||
|
||||
const Uint64 beforeMap = buffer->GetChangeSerial();
|
||||
buffer->AcquireMemoryRange(Range1D{0, kSize}, BufferMappingAccessBit::Write | BufferMappingAccessBit::Persistent);
|
||||
ASSERT_TRUE(PersistentMapTracker::IsLivePersistentMap(*buffer));
|
||||
EXPECT_EQ(buffer->GetChangeSerial(), beforeMap) << "the rising-edge state record went out with the push disabled";
|
||||
|
||||
const Uint64 before = MG_Util::PipeStats::TotalBytes(MG_Util::PipeStats::ByteClass::PersistentMapPush);
|
||||
MG_Record::PushPersistentMapsBeforeVerb();
|
||||
EXPECT_EQ(PersistentMapTracker::Instance().BlocksPushed(), 0u);
|
||||
EXPECT_EQ(MG_Util::PipeStats::TotalBytes(MG_Util::PipeStats::ByteClass::PersistentMapPush), before)
|
||||
<< "MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0 must ship nothing, so that "
|
||||
"PersistentCoherentMapScenario goes red under it";
|
||||
|
||||
const Uint64 beforeUnmap = buffer->GetChangeSerial();
|
||||
buffer->ReleaseMemory(/*landStagedWrites=*/true);
|
||||
EXPECT_EQ(buffer->GetChangeSerial(), beforeUnmap + 1)
|
||||
<< "with the push off the unmap must emit only its own NotifyFlushMappedRange - a "
|
||||
"falling-edge record here delivers a whole buffer the control exists to withhold, "
|
||||
"and a negative control that still delivers the bytes is not a control";
|
||||
}
|
||||
|
||||
// The set does not keep a pointer to a dead buffer.
|
||||
TEST_F(SplitBufferSet, ADestroyedBufferLeavesTheSet) {
|
||||
{
|
||||
@@ -871,9 +838,6 @@ TEST(SplitBufferSet, TheLastBlockIsTheRemainderAndNotAWholeBlock) {
|
||||
TEST(SplitBufferSet, BothEdgesOfAWriteMapPublishOneStateRecord) {
|
||||
MGL_SPLIT_ONLY_OR_SKIP();
|
||||
}
|
||||
TEST(SplitBufferSet, AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited) {
|
||||
MGL_SPLIT_ONLY_OR_SKIP();
|
||||
}
|
||||
TEST(SplitBufferSet, ADestroyedBufferLeavesTheSet) {
|
||||
MGL_SPLIT_ONLY_OR_SKIP();
|
||||
}
|
||||
|
||||
@@ -4326,12 +4326,10 @@ TEST(DirectGLESBufferDrawProbe, UnderSplitTheRecordAloneAnswersTheLiveHostMapQue
|
||||
// case reaches is optional.
|
||||
const Uint64 previousPush = MG_Config::Features.PipePush;
|
||||
const auto previousTransport = MG_Config::Transport;
|
||||
const Uint32 previousBlockKb = MG_Config::RecordArm.PersistentBlockKb;
|
||||
MG_Pipe::MGPipeResourceOps ops{};
|
||||
MG_Config::Features.PipePush |= MG_Pipe::kMGPipeSubsystemResources;
|
||||
MG_Pipe::MGPipeSetResourceOps(&ops);
|
||||
MG_Config::Transport = MG_Config::TransportMode::InProcess;
|
||||
MG_Config::RecordArm.PersistentBlockKb = 64;
|
||||
// P5 c1 / R-8: UNDER SPLIT THE OP TABLE IS NO LONGER THE ARMING CONDITION, and this case is
|
||||
// the first place that shows. `MGPipeSetResourceOps(&ops)` is the SERVER's registration; the
|
||||
// client's liveness gate now reads the caps mirror's consumer mask instead, because under a
|
||||
@@ -4424,7 +4422,6 @@ TEST(DirectGLESBufferDrawProbe, UnderSplitTheRecordAloneAnswersTheLiveHostMapQue
|
||||
BufferImpl::g_backendBufferResources.ReleaseByHandle(res);
|
||||
}
|
||||
|
||||
MG_Config::RecordArm.PersistentBlockKb = previousBlockKb;
|
||||
MG_Config::Transport = previousTransport;
|
||||
MG_Pipe::MGPipeSetResourceOps(nullptr);
|
||||
MG_Config::Features.PipePush = previousPush;
|
||||
|
||||
@@ -79,8 +79,8 @@
|
||||
// per sub-draw), so this class is Espryt-only by construction.
|
||||
// persistent-map-push WIRED IN P5 (b1), and only a split build can ever move it. The one
|
||||
// site is BufferObject::PushMappedSpanBlock, i.e. the client shipping
|
||||
// one MOBILEGL_IPC_PERSISTENT_BLOCK_KB block of a persistently mapped
|
||||
// span because MGPipeApplyMapPersistent declined the adoption (R-6,
|
||||
// one 64 KiB block of a persistently mapped span because
|
||||
// MGPipeApplyMapPersistent declined the adoption (R-6,
|
||||
// tier T2). Zero in every monolith build, and that zero is CORRECT
|
||||
// rather than missing: a persistent map there is a permanent address
|
||||
// space donation (D4/D-B4), the application writes straight into GPU
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| T1 | server 导出 opaque fd | 仅 Adreno 的 Vulkan 路径 |
|
||||
| T2 | 拒绝,client 侧推送 | 永久正确回退;**今天 split 用的档**(`MOBILEGL_IPC_ADOPT_TIER=2`),stream 数据面上强制(P11 A1:两端握手时 `Transport::SettleAdoptTierAtHandshake` 对 0/1 打一行 `Refuse{AdoptTierOnStream}` 并走 T2;共享段上 client 握手期 `Fatal{UnimplementedAdoptTier}`,[`CONTRACT-P11.md`](../../archive/contracts/CONTRACT-P11.md) §1) |
|
||||
|
||||
T2 下 client 侧推送三件套:不做 map/unmap 命令对(payload 带 `hasLiveHostWrites`);在每个 validate 点按块(`MOBILEGL_IPC_PERSISTENT_BLOCK_KB`,默认 64)推送可达的已映射 buffer,脏页追踪 + 哈希抑制只发变化的块(P5d);门 `PersistentCoherentMapScenario`。`mpr` 数的是每一次 `MapPersistent` 发射(铸成或拒绝都算),所以在 monolith 下也可断言。
|
||||
T2 下 client 侧推送三件套:不做 map/unmap 命令对(payload 带 `hasLiveHostWrites`);在每个 validate 点按 64 KiB 块推送可达的已映射 buffer,脏页追踪 + 哈希抑制只发变化的块(P5d);门 `PersistentCoherentMapScenario`。`mpr` 数的是每一次 `MapPersistent` 发射(铸成或拒绝都算),所以在 monolith 下也可断言。
|
||||
|
||||
### 12.1 采纳档的握手期结算
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ CMake:`MOBILEGL_BUILD_DISAGGREGATED`(OFF)、`MOBILEGL_BUILD_DISAGGREGATED_
|
||||
| `MOBILEGL_IPC_BATCH_WAITS` | 1 | lockstep 下值类记录发布即返回;verify 强制 0 |
|
||||
| `MOBILEGL_IPC_EVENT_WAIT_MS` | 2000 | 反向事件遇满环时 server 等 client 排空的整笔预算(§11.7) |
|
||||
| `MOBILEGL_IPC_WIRE_DEFERRED_MB` | 64 | Magma wire 臂延迟回收的水位线;`0` 是 M2 阴性对照 |
|
||||
| `MOBILEGL_IPC_PERSISTENT_BLOCK_KB` / `_PERSISTENT_HASH_SUPPRESS` | 64 / 1 | persistent-map 推送粒度 / 只推变化的块;`0` 是对照 |
|
||||
| `MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS` | 1 | persistent-map 推送只推变化的块(粒度固定 64 KiB,`PersistentMapTracker::BlockBytes()`);`0` 是整段推送的 A/B 对照 |
|
||||
| `MOBILEGL_IPC_ADOPT_TIER` | 未设 = T0 | 未设(用户 2026-09-29 定为缺省)= 能用就 T0,不能用(stream、无 AHB、POST 失败、server 不允许)安静回退 T2:只 MGLOG_D、照样计数;`0` = 点名要 T0,回退有具名行(A1 的 `Refuse{AdoptTierOnStream}` 等);`1` = T1 已关,具名拒绝后 T2;`2` = T2(P11 前的缺省)。`CONTRACT-P11.md` B2 |
|
||||
| `MOBILEGL_IPC_ALLOW_ADOPT_T0` | 1 | server 自有:`0` = 永不批准 T0(会话走 T2),经 `ServerSpawn` 保留 |
|
||||
| `MOBILEGL_IPC_STRICT_ERRORS` / `MOBILEGL_IPC_AUDIT` / `MOBILEGL_IPC_ROLE_SPLIT_STATE` | 0 / 0 / 1 | 残余输入读升级为 Fatal / 退休 staging 填 `0xDD` / 双块(P5f;P15 起默认开,`0` 关闭,阴性对照显式设 0;双块下 barriered fill 写 client 块,不再 quiesce applier) |
|
||||
|
||||
@@ -58,6 +58,7 @@ them wrong.
|
||||
| 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 |
|
||||
| 2026-10-18 | unit `SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited` (and its skip stub in the non-disaggregated half), and the `MOBILEGL_IPC_PERSISTENT_BLOCK_KB` knob with its `0` arm in the shipped tracker (`PersistentMapTracker::PushBlocksForChecked`'s early return and once-per-process warning, `BufferObject::NotePersistentMapStateChanged`'s, the `persistent-block=` field of the `Config: IPC` line) | Test / unit; product code | `0` was never a product mode, only E3(a)'s negative control, retired above; the unit case pinned that `0` shipped nothing; the block size is now the constant 64 KiB (`PersistentMapTracker::BlockBytes()`) | `PersistentCoherentMapScenario.ThePushIsTheOnlyRouteAWriteTakesToTheServer` |
|
||||
|
||||
## Kept after investigation
|
||||
|
||||
|
||||
@@ -11624,7 +11624,6 @@
|
||||
"SplitBufferSet.AFaultedMapTheDrawDidNotBindStillShipsBeforeTheDrawThatDoes",
|
||||
"SplitBufferSet.AShadowThatFailsThePageGranularTestKeepsTheInwardAlignmentAndItsEdges",
|
||||
"SplitBufferSet.ASubPageMapIsOneProtectedPageAndAWriteThroughItFaults",
|
||||
"SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited",
|
||||
"SplitBufferSet.BothEdgesOfAWriteMapPublishOneStateRecord",
|
||||
"SplitBufferSet.MembershipIsSyncPersistentMappedRangesOwnEarlyOutChain",
|
||||
"SplitBufferSet.Row0EverySsboBindingPointIsMarkedByADraw",
|
||||
@@ -15948,7 +15947,6 @@
|
||||
"SplitBufferSet.AFaultedMapTheDrawDidNotBindStillShipsBeforeTheDrawThatDoes",
|
||||
"SplitBufferSet.AShadowThatFailsThePageGranularTestKeepsTheInwardAlignmentAndItsEdges",
|
||||
"SplitBufferSet.ASubPageMapIsOneProtectedPageAndAWriteThroughItFaults",
|
||||
"SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited",
|
||||
"SplitBufferSet.AnOlderWritebackCannotRetireANewerGpuWriteMark",
|
||||
"SplitBufferSet.BothEdgesOfAWriteMapPublishOneStateRecord",
|
||||
"SplitBufferSet.MembershipIsSyncPersistentMappedRangesOwnEarlyOutChain",
|
||||
@@ -17437,7 +17435,6 @@
|
||||
"SplitBufferSet.AFaultedMapTheDrawDidNotBindStillShipsBeforeTheDrawThatDoes",
|
||||
"SplitBufferSet.AShadowThatFailsThePageGranularTestKeepsTheInwardAlignmentAndItsEdges",
|
||||
"SplitBufferSet.ASubPageMapIsOneProtectedPageAndAWriteThroughItFaults",
|
||||
"SplitBufferSet.AZeroBlockSizeTurnsThePushOffRatherThanMakingItUnlimited",
|
||||
"SplitBufferSet.AnOlderWritebackCannotRetireANewerGpuWriteMark",
|
||||
"SplitBufferSet.BothEdgesOfAWriteMapPublishOneStateRecord",
|
||||
"SplitBufferSet.MembershipIsSyncPersistentMappedRangesOwnEarlyOutChain",
|
||||
|
||||
Reference in New Issue
Block a user